From a548a3f951ce3870daa820f4b9cc9e9a0b3edfbb Mon Sep 17 00:00:00 2001 From: Henry Winkel Date: Sun, 27 Jul 2025 15:32:55 +0200 Subject: [PATCH] ADD: added initial working version --- src/main/java/com/example/App.java | 4 +- .../java/com/example/FileScannerTask.java | 68 +++++++++++++----- .../com/example/FileSorterController.java | 31 +++++--- src/main/java/com/example/FileSorterTask.java | 54 ++++++++++++-- target/classes/com/example/App.class | Bin 1946 -> 2215 bytes .../classes/com/example/FileScannerTask.class | Bin 2679 -> 5475 bytes .../com/example/FileSorterController.class | Bin 7414 -> 7467 bytes .../classes/com/example/FileSorterTask.class | Bin 5243 -> 6354 bytes 8 files changed, 123 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/example/App.java b/src/main/java/com/example/App.java index 0dfbe27..fc0df54 100644 --- a/src/main/java/com/example/App.java +++ b/src/main/java/com/example/App.java @@ -20,8 +20,9 @@ public class App extends Application { scene = new Scene(loadFXML("primary"), 640, 480); stage.setScene(scene); stage.show(); + System.out.println("help"); - + System.err.println("App started with scene: " + scene); } @@ -36,6 +37,7 @@ public class App extends Application { public static void main(String[] args) { launch(); + } } \ No newline at end of file diff --git a/src/main/java/com/example/FileScannerTask.java b/src/main/java/com/example/FileScannerTask.java index 84e8e89..59e2fc5 100644 --- a/src/main/java/com/example/FileScannerTask.java +++ b/src/main/java/com/example/FileScannerTask.java @@ -1,6 +1,8 @@ package com.example; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -36,24 +38,43 @@ public class FileScannerTask extends Task> { * @throws Exception If an error occurs during the file scanning process. */ protected Map call() throws Exception { - int filesAmount = countFilesInDirectory(); - + long filesAmount = countFilesInDirectory(); + if (filesAmount == 0) { + updateProgress(filesAmount, filesAmount); + return fileTypeCounts; // Return empty map if no files found + } java.io.File directory = new java.io.File(directoryPath); if (directory.isDirectory()) { - java.io.File[] files = directory.listFiles(); - if (files != null) { - int i = 0; - for (java.io.File file : files) { - if (file.isFile()) { - String fileType = getFileExtension(file); - fileTypeCounts.put(fileType, fileTypeCounts.getOrDefault(fileType, 0) + 1); - } + java.util.concurrent.atomic.AtomicInteger i = new java.util.concurrent.atomic.AtomicInteger(0); - updateProgress(i, filesAmount); - i++; - } - } + Files.walk(directory.toPath()) + .filter(Files::isRegularFile) + .forEach(path -> { + try { + String fileType = getFileExtension(path.toFile()); + java.nio.file.attribute.BasicFileAttributes attrs = Files.readAttributes(path, java.nio.file.attribute.BasicFileAttributes.class); + // You can now access metadata like attrs.size(), attrs.creationTime(), attrs.lastModifiedTime(), etc. + fileTypeCounts.put(fileType, fileTypeCounts.getOrDefault(fileType, 0) + 1); + updateProgress(i.get(), filesAmount); + i.incrementAndGet(); + } catch (Exception e) { + e.printStackTrace(); + } + }); + + // java.io.File[] files = directory.listFiles(); + // if (files != null) { + // for (java.io.File file : files) { + // if (file.isFile()) { + // String fileType = getFileExtension(file); + // fileTypeCounts.put(fileType, fileTypeCounts.getOrDefault(fileType, 0) + 1); + // } + + // updateProgress(i.get(), filesAmount); + // i.incrementAndGet(); + // } + // } } return fileTypeCounts; @@ -64,14 +85,25 @@ public class FileScannerTask extends Task> { * * @param directoryPath The path to the directory. */ - public int countFilesInDirectory() { + public long countFilesInDirectory() { java.io.File directory = new java.io.File(directoryPath); if (directory.isDirectory()) { - java.io.File[] files = directory.listFiles(); - if (files != null) { - return files.length; + long fileCount = 0; + try { + fileCount = Files.walk(Paths.get(directoryPath)) + .filter(Files::isRegularFile) + .count(); + System.out.println("Number of files in directory: " + fileCount); + return fileCount; + } catch (java.io.IOException e) { + e.printStackTrace(); } + + // java.io.File[] files = directory.listFiles(); + // if (files != null) { + // return files.length; + // } } return 0; } diff --git a/src/main/java/com/example/FileSorterController.java b/src/main/java/com/example/FileSorterController.java index 188fdaf..8c896b9 100644 --- a/src/main/java/com/example/FileSorterController.java +++ b/src/main/java/com/example/FileSorterController.java @@ -34,6 +34,8 @@ public class FileSorterController { @FXML private void scan() throws IOException { + + progressBar.setProgress(0); errormessages.setText(""); // Clear previous error messages filesDiagram.getData().clear(); // Clear previous data from the bar chart // Check if the directory is valid @@ -81,12 +83,19 @@ public class FileSorterController { * @param fileTypeCounts A map where keys are file types and values are their respective counts. */ private void updateBarChart(Map fileTypeCounts) { - fileTypeCounts.forEach((fileType, count) -> { - javafx.scene.chart.XYChart.Series series = new javafx.scene.chart.XYChart.Series<>(); - series.setName(fileType); - series.getData().add(new javafx.scene.chart.XYChart.Data<>(fileType, count)); - filesDiagram.getData().add(series); - }); + if (fileTypeCounts == null || fileTypeCounts.isEmpty()) { + System.out.println("No files found or no file types to display."); + errormessages.setText("No files found or no file types to display."); + return; + + }else{ + fileTypeCounts.forEach((fileType, count) -> { + javafx.scene.chart.XYChart.Series series = new javafx.scene.chart.XYChart.Series<>(); + series.setName(fileType); + series.getData().add(new javafx.scene.chart.XYChart.Data<>(fileType, count)); + filesDiagram.getData().add(series); + }); + } } @@ -135,9 +144,15 @@ public class FileSorterController { filesamount.setText(String.valueOf(result.values().stream().mapToInt(Integer::intValue).sum())); }); service.start(); + // try { + // service.wait(); + // } catch (InterruptedException e) { + // e.printStackTrace(); + // errormessages.setText("Operation was interrupted."); + // } } - progressBar.paddingProperty().unbind(); - // progressBar.setProgress(0); // Reset progress bar before starting the service + progressBar.progressProperty().unbind(); + progressBar.setProgress(0); // Reset progress bar before starting the service final FileSorterService service = new FileSorterService(); service.setDirectoryPath(directory.getAbsolutePath()); diff --git a/src/main/java/com/example/FileSorterTask.java b/src/main/java/com/example/FileSorterTask.java index 9b4d26e..fa77dc5 100644 --- a/src/main/java/com/example/FileSorterTask.java +++ b/src/main/java/com/example/FileSorterTask.java @@ -30,8 +30,32 @@ public class FileSorterTask extends Task { protected Integer call() throws Exception { System.out.println("Scanning directory: " + directoryPath); int filesAmount = FileScannerTask.countFilesInDirectory(directoryPath); + + java.nio.file.Files.walk(java.nio.file.Paths.get(directoryPath)) + .filter(java.nio.file.Files::isRegularFile) + .forEach(path -> { + try { + // System.out.println("Processing file: " + path); + String[] parts = path.toString().split(java.util.regex.Pattern.quote(java.io.File.separator)); + java.nio.file.attribute.BasicFileAttributes attrs = java.nio.file.Files.readAttributes(path, java.nio.file.attribute.BasicFileAttributes.class); + // System.out.println(parts[(parts.length - 2)] + " - Creation Year: " + getCreationYear(path)); + if (parts[(parts.length - 2)].equals(String.valueOf(getCreationYear(path)))) { + // System.out.println("Skipping file: " + path + " due to invalid year"); + return; // Skip files with invalid year + + }else { + System.out.println("Processing file: " + path + " with valid year"); + } + // You can now access metadata like attrs.size(), attrs.creationTime(), attrs.lastModifiedTime(), etc. + + // Here you can add logic to handle file types if needed + } catch (Exception e) { + e.printStackTrace(); + } + }); + // Use a Set to track which year folders have already been created - AtomicInteger i = new AtomicInteger(0); + AtomicInteger i = new AtomicInteger(0); java.util.Set createdFolders = new java.util.HashSet<>(); java.nio.file.Files.list(java.nio.file.Paths.get(directoryPath)) .filter(java.nio.file.Files::isRegularFile) @@ -39,11 +63,8 @@ public class FileSorterTask extends Task { try { java.nio.file.attribute.BasicFileAttributes attrs = java.nio.file.Files.readAttributes(path, java.nio.file.attribute.BasicFileAttributes.class); // Use the earlier of creationTime and lastModifiedTime - java.time.Instant creationInstant = attrs.creationTime().toInstant(); - java.time.Instant modifiedInstant = attrs.lastModifiedTime().toInstant(); - java.time.Instant instant = creationInstant.isBefore(modifiedInstant) ? creationInstant : modifiedInstant; - java.time.ZonedDateTime zdt = java.time.ZonedDateTime.ofInstant(instant, java.time.ZoneId.systemDefault()); - String year = String.valueOf(zdt.getYear()); + + String year = String.valueOf(getCreationYear(path)); java.nio.file.Path targetDir = java.nio.file.Paths.get(directoryPath, year); // Only create the directory if it hasn't been created yet @@ -52,7 +73,7 @@ public class FileSorterTask extends Task { } java.nio.file.Path targetPath = targetDir.resolve(path.getFileName()); - java.nio.file.Files.copy(path, targetPath, java.nio.file.StandardCopyOption.REPLACE_EXISTING); + java.nio.file.Files.move(path, targetPath, new java.nio.file.CopyOption[0]); updateProgress(i.get(), filesAmount); i.incrementAndGet(); } catch (Exception e) { @@ -62,6 +83,25 @@ public class FileSorterTask extends Task { // Implementation of file scanning logic goes here return 0; // Placeholder return value } + /** + * Gets the creation year of a file based on its attributes. + * + * @param path The path to the file. + * @return The year of creation or -1 if an error occurs. + */ + private int getCreationYear(java.nio.file.Path path) { + try { + java.nio.file.attribute.BasicFileAttributes attrs = java.nio.file.Files.readAttributes(path, java.nio.file.attribute.BasicFileAttributes.class); + java.time.Instant creationInstant = attrs.creationTime().toInstant(); + java.time.Instant modifiedInstant = attrs.lastModifiedTime().toInstant(); + java.time.Instant instant = creationInstant.isBefore(modifiedInstant) ? creationInstant : modifiedInstant; + java.time.ZonedDateTime zdt = java.time.ZonedDateTime.ofInstant(instant, java.time.ZoneId.systemDefault()); + return zdt.getYear(); + } catch (java.io.IOException e) { + e.printStackTrace(); + return -1; // Return an invalid year if an error occurs + } + } } diff --git a/target/classes/com/example/App.class b/target/classes/com/example/App.class index 3c4b267e30ce7520650993a04429acf43e186cff..bee14f29845dc66b647103e5720efe98f99e4be7 100644 GIT binary patch delta 907 zcmZvZT~pIQ7=_O^r71Ch6ew04>|($bQqB~77-QuQCe z-Z=gNZ-om4W_0w{ALaNaWkz(o*`4g3ea<;=KGuDzmwx^_{05*0Z+9fYRj$TmTorMJ z;bcZ#RU^7;q#}v+f~93;T*Gw+Ay>2*niS_cor_GEX~Rlbrlw}2UUW0Kmoz;u;RgCd z^fEO3M<^qTeg-jbzts)Gg(|#q#m}PiR5Uzgr@19#!12{gQ$h@bBJTX1&QZ&_i+hAz zRrR7ao@D4aLOR6p`HZ$;MZ*=B<0d{TKP+PeqYTYie&8D5HLh@tgeE+cpXWU`$ z2 z><>(G#I2BU)_E+G5IBJeJmNn*?dAB4k6k##V>`p-7d%rg?qT*j=0B6F5~o5qhX%AA zvv08pq-h}AMQB8=MiMD!2fAsueZ0a~#P+fDZ=NvR=(K75)YuVX89F@>kadg=8Hlb2QSt_5v2eHQOp2aAed*8kH+;h%-A9lRUx<7tzegy_tTz8F(9y5xE6!|03 zllWB}HsYmvSbe#?xKtl5PPybc=~1Fju}i;EzJ6;2-9rjL0oPW;+UnCrI66HZMbF~- zh2@;^4ttb2t!<;S-(`ezHfI&t7I~!+udH~Sr=ouuea;{kJ#0pG$@HbT>~V!LJz)ka z($CGgz~+WxduzSv%|&t3;}(z%wbC0DM#noi%&o&TczVS(QG3tmFy96OdL4! zGspFseX!?5i^NUA`*10w%boyX3;hh}?{@dv;7m^SZgL7XIP-}M(a{YqedFp!K{ahO z8M^4;z(4YP5(dF^i0nAmgteUsCew_}RI1|`U%396>i>QY%V|9cTfbbI7;>26wq%3p YRCtCvX;<+;<}r_?N`85s8jsoi7vf`Dm;e9( diff --git a/target/classes/com/example/FileScannerTask.class b/target/classes/com/example/FileScannerTask.class index 7b2024f86291bf3ff1e486aa8edba7b98dd4ae4e..a7f354f44eb6a49e6df60452d52e64bc7120c975 100644 GIT binary patch literal 5475 zcmcIo3wRt=75--*nPfYVG;IQbwpmIG$u@MM6k4*SG)-HYm^QH~sZA?%vO7tJ?9RlU z*)~N1U%W&`Eh?a*qJj@lK-j(n@r8=`em@YO_bv#P zsbt!=(uI89u-v5hrr@}YnK#m|o!>j4yW&?@W|e7~?rH^1 zZ2<}2jrJi0k#0L<#1KZkhFNG(5N>N9ssr8D5JioOxe88`0HkXHwB2Rk8+B)#KF2Tz z^`7HW34M?T86Dx z$epgC4ed;DVKSq;#z5X4%Nq{iMcaCN+lN#vQJ_ipOk46Qh6K(KvDd^?Qp1@zOTjGD zsa8I$;%o)&(`G_F zUKKrLXC;PJYBjtFeT)sm;2L=a=lNbgm&Td=Q?OY>KL)5yPYY@)7;l@A-vLesYHYg9 zrh0>x%TQU4P9ev#7f82g7{pcu>ZqMxucz6C;?trjPZF(QmLP!Bl@kP4p!Bi@m0KAJ z?Rn_4mPMzS3YNS8x7is7T|GU)P9Y0l#Y+`5$Ycb1V+@x-SF!6DUJ1^SS0hNX*v1Tc zn3|@g`J@UcEb*w!GfBQigs@ITYE;9RsOzY#>pGZVd%v{WvAvFKjQcYRa09*92ul_M=|mMpROXJ{%ik*0~hPPlJYcp$D zV`7QsnkPTJRm0oxcEWQCBkT=aszoq*rgdm1Zq{&%aA=lm_t|@le7EixwRk5zELank zy@${uA`S{_#m)1%He-7pF$HW!v;A-cw*u9$`bRG1ZXzYtmiKFzhxt^O)pH{meGwOg z6a3g!v%8(E#RnCfSlz+78c$T3_lGrn1b4D1O=pWSR>aYG9K7-Gah`aS{!4TYUu4b_>#tSS@ApK7>a#d|4D- zEj!qda7)0!xZwv8y(@N)!9Jkk9R^~#3Qmwd*g*7Sn z*0Qif?T~^ZT8@G9<>DsJEP;`#i6Z*{+egpj%yWZe z^38Vh7%*sZOIKfmpB}YXl_)sefM1I`|DA>p;C2fBwgI<4hwM-T{wQSsqTyq>yI#eg zpR=t}^l!fACpG*?YW^oR$M7FKt>TD+MaLw@3!k?W*icH%B%V=l)Bisie(rVzl2-~* zU}&1aK2@tI3R=CxTihOvkCOFH+_d85En#Pz5?YTq6wA(LII6;P@#145Fde~ErAEPm znMK*eJvQPLrYFoze~5oPl*%WbFgaQ$pJNaS9u zw(m#N{b;^NPC1d+Mnrg>$LoA5T7bFiEiD{r_9o*boXj_>kw)2c#PUnk3pf^`saD_o zDbna;l#24pjzkd)*RDy(b(B;y{xTlSN2tL>G zyU2m?QN?R<6@3&rAjgkjo)>@aSbSe@;9No7Hrl>+Q%A$nB3{3G{;fE1en$~+iezrX z@g4IcyNbB6h@0+id`E>h%`$IS^Lh=VdMzV#9kY6UAZl%8+PC3d(xWI@aVxzHamGBn z8}FfY;TwPIc^ZpV?BrG!?`36#I3$YHtA`{<6~0GH%neEA*2uwq(xRwW3V0S9)=~Ry zoL(s}QOkmJo|+=wCx8UiC{hhey&)zVJq5*-(4^f>)cDL2frJBWJ}a&v!Yv?bDb&{J}_vqk`Ek#Jg~;RE>OL3}REP1r+4d?~U^ zzJDc*Z3!mj>sQ5D_k8%~wmT4`nrIQIOPOoGPIR^kNl% zIXE9%x!2sz5y9u>GHb)-%nakZ^gqIRYw=pH^H#oHjvw;sW zVT8C~`Cy-KglOY2+7IE!erg}bPxyWs$A3i(zrpYE2l@0T{1tzfPyfKb@NYZ|E)I(5 O!R*XRSc$TvTK)@gBcf^m delta 1381 zcmZWpO;cNC6n@^^%f0z{`3g-Tg_I%?LI{bVAWfmtmLgFCRS=|V%`LfvTf)7V+%(XI zj3XVVE62I3jx)~arkgHs#))4u=&B2s?p^sK+*t9vH%w{AMb7(i-gBPkIp^H`761E; z|M!1?J_7I>?tSN<@LbQR7+~Ocw7Xi$uu`)|QTHQ?L5={p*bQ+cFw77z$}>huU$?E& z9)lDcyeYgXj+Zgw45=3);`j>3tKzX@lGuZ;-0;m2InH+6*ki;LD#%X>z92_y98)Wbuv?i)DFl zhqjGNwzj@S1eUeiMP0@6mw&bgGD7JG93SGA^GNNzk;82j8biyetR=f-m<5h?sm`y>>Be)A(Fq@U&X7-O zN$<1I&;UP8!-IGYFHQb}=vw@HwElotHc>o%d_|c3f9RgB{v z-5=l*!W20NmFxqYBhjEN2Ux@n8jV)$;%&SG5B4L}fh8;xU>{ZgU2@Bm_9|A$-9QPV zScO6rdyf*_gnUeBJ{63qh^knlQKH=%aE!?p?#cbk)AWMpG(v%-j@469az+ID$u`pd zQ=%i$+VfmH=7-#NG}DrFrh?)98F0*^jlP5q;@O1^x-sv{zEBT7k`N1 z8ZX#C=q941u8*|Up+7l+KJP-)7(9=gO+0~;IC?BS2AoW=aeswkSJ6WGLR5t?W$B`C zLX^JF;XKt)p_A_!htU5ybO{bj{6(B__<}gd6cr<_?`IP&$r?Vo9Qhg@5t>C^&VP%h zL`2Tj5ZkPwco?)!C*~{x0vlutRGv*Lfk9Q>a-Ig;6QZSzJiYjsNO{QLg%UMfa?9ZZ xdy0M)IqE6O&U9Onl^v_Co!QRkZIMJpV0hfAROo@|myqdke^uA+l1y>4_a9v1@Xi1L diff --git a/target/classes/com/example/FileSorterController.class b/target/classes/com/example/FileSorterController.class index 46864a1b3811cd1c7943320ee38f132bb99c3a9d..61ccee9339a41b563df52813bf32a89cf1ef2d26 100644 GIT binary patch delta 3249 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 RAfHClHi~dx$bA&~{{;2btgZk6 delta 3256 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 delta 1978 zcmZXV33yc16~}*Xwmb9YO=hy^v1l3$4MWlt1c6CVLO_@{EIJ4VYwb8Qgn?ux&Wu!Q z+f*&uR@(}<3rba5iYT}MVwi+#t*vd*E@JmuwfkZ>yVq)==M92dzc0D>ynFulEdO)P zou_8J)Mh?@eEeZxj$s@ym$~!~PkX$Bw^}G>7w36!>%TG7v1_s*Pe%aIIH&|q`nDg~j?snf&-lmA_z3xfwx6`MOy5n`rEmpA7z?V#= zGQ%ZKQ!BNKGWyVeY{lnX5qtkPLe$D2%6bFpI0sqiZy#&f02K&D{P&szPg_X+)g zX;)_~YN<2u4&N`lTDS2Dg*Ircl;Jcay(n4AIF2kn$)|K};DSrHvEAYp zZZ%K?nNoiySuk+7O^ch%<}(g~w;9w+i}d|}19SzsgU>2<8iXpkO5;e=SbUCMVkDVP z>np4#VR*N`ITRI!_gLJ;-TKkc#^!z8tGLIY=JkEDGFe)0aUb{V*;Uj0`#4~6kO%a- zs(HqPdS}(dkpPDoQPw(Q(7GE4s ztcovRV$gCjnbY0*#=BikaUZgHm@mqNq{OB{e_P)M-K(1P^HmFKI{1=B7q^-ieA(hF zJf^$D6I(j?n#I>0HpAIms*oAVYpUHo`6^>c3d5V<7C~g$M&usK%Pr z5&rII{$(-D6=B6cWkPIQj$bse;<;R=&?_BV%t(CyHE7lO>P87E?BawzRx{u5>TvDG zk)wF=$ZL~0NK^C>p>fWDQCb|i%$vK9(9!QcOy{yA%@84#}~Zv$>Ra;*x9Axr}#-;iMoe(VaZG9Cu`qycj9L)QiR=ng#+QwTfiO z?v0L;)(7e*xrIpmWPRPp`Z62t5sh@6td1?@Mvgp0Tn?#nA{LCN@evZ;e%n)1klf{7 zDdx4kV_anjSMQDa9QoRlva)@)8fD8Z_-)@Fytaz@ZGV{?%WRDW?7%3WF0&(MMh}e; z@(7XrZre-@|ef{Vrmb?XfMncBtQdkWsn! zg*DOkQ6AYcdCMq|iuBbrdoZ2oMmc(*lG1J&