Searching files in a directory and pairing them ba

2019-09-13 20:36发布

问题:

I have been attempting to program a solution for ImageJ to process my images.

I understand how to get a directory, run commands on it, etc etc. However I've run into a situation where I now need to start using some type of search function in order to pair two images together in a directory full of image pairs.

I'm hoping that you guys can confirm I am on the right direction and that my idea is right. So far it is proving difficult for me to understand as I have less than even a month's worth of experience with Java. Being that this project is directly for my research I really do have plenty of drive to get it done I just need some direction in what functions are useful to me.

I initially thought of using regex but I saw that when you start processing a lot of images (especially with imagej which it seems does not dump data usage well, if that's the correct way to say it) that regex is very slow.

The general format of these images is:

  • someString_DAPI_0001.tif
  • someString_GFP_0001.tif
  • someString_DAPI_0002.tif
  • someString_GFP_0002.tif
  • someString_DAPI_0003.tif
  • someString_GFP_0003.tif

They are in alphabetical order so it should be able to go to the next image in the list. I'm just a bit lost on what functions I should use to accomplish this but I think my overall while structure is correct. Thanks to some help from Java forums. However I'm still stuck on where to go to next.

So far here is my code: Thanks to this SO answer for partial code

int count = 0;
getFile("C:\");

string DAPI;
string GFP;


private void getFile(String dirPath) {
    File f = new File(dirPath);
    File[] files = f.listFiles();

    while (files.length > 0) {
        if (/* File name contains "DAPI"*/){
            DAPI = File f;
            string substitute to get 'GFP' filename
            store GFP file name into variable
            do something(DAPI, GFP);
        }
        advance to next filename in list
    }
}

As of right now I don't really know how to search for a string within a string. I've seen regex capture groups, and other solutions but I do not know the "best" one for processing hundreds of images.

I also have no clue what function would be used to substitute substrings.

I'd much appreciate it if you guys could point me towards the functions best for this case. I like to figure out how to make it on my own I just need help getting to the right information. Also want to make sure I am not making major logic mistakes here.

回答1:

It doesn't seem like you need regex if your file names follow the simple pattern that you mentioned. You can simply iterate over the files and filter based on whether the filename contains DAPI e.g. see below. This code may be oversimplification of your requirements but I couldn't tell that based on the details you've provided.

import java.io.*;


public class Temp {

  int count = 0;

  private void getFile(String dirPath) {
    File f = new File(dirPath);
    File[] files = f.listFiles();

    if (files != null) {
      for (File file : files) {
        if (file.getName().contains("DAPI")) {
          String dapiFile = file.getName();
          String gfpFile = dapiFile.replace("DAPI", "GFP");
          doSomething(dapiFile, gfpFile);
        }
      }
    }
  }

  //Do Something does nothing right now, expand on it.
  private void doSomething(String dapiFile, String gfpFile) {
    System.out.println(new File(dapiFile).getAbsolutePath());
    System.out.println(new File(gfpFile).getAbsolutePath());
  }

  public static void main(String[] args) {
    Temp app = new Temp();
    app.getFile("C:\\tmp\\");
  }

}

NOTE: As per Vogel612's answer, if you have Java 8 and like a functional solution you can have:

private void getFile(String dirPath) {
  try {
    Files.find(Paths.get(dirPath), 1, (path, basicFileAttributes) -> (path.toFile().getName().contains("DAPI"))).forEach(
      dapiPath -> {
        Path gfpPath = dapiPath.resolveSibling(dapiPath.getFileName().toString().replace("DAPI", "GFP"));
        doSomething(dapiPath, gfpPath);
      });
  } catch (IOException e) {
    e.printStackTrace();
  }
}

//Dummy method does nothing yet.
private void doSomething(Path dapiPath, Path gfpPath) {
  System.out.println(dapiPath.toAbsolutePath().toString());
  System.out.println(gfpPath.toAbsolutePath().toString());
}


回答2:

Using java.io.File is the wrong way to approach this problem. What you're looking for is a Stream-based solution using Files.find that would look something like this:

 Files.find(dirPath, 1, (path, attributes) -> {
     return path.getFileName().toString().contains("DAPI");
 }).forEach(path -> {
    Path gfpFile = path.resolveSibling(/*build GFP name*/);
    doSomething(path, gfpFile);
 });

What this does is:

  • Iterate over all Paths below dirPath 1 level deep (may be adjusted)
  • Check that the File's name contains "DAPI"
  • Use these files to find the relevant "GFP"-File
  • give them to doSomething

This is preferrable to the files solution because of multiple things:

  1. It's significantly more informative when failing
  2. It's cleaner and more terse than your File-Based solution and doesn't have to check for null
  3. It's forward compatible, and thus preferrable over a File-Based solution

Files.find is available from Java 8 onwards