Hisushi
Hisushi

Reputation: 67

file.delete() only works the first time

at the moment I am writing a small programm to check whether a file is in a database or not. Moreover I check whether the hash in the database has been computed correctly (here: sha256). The filename is the (old and maybe wrong) sha from the file.

For better understanding a small workflow:

  1. Get file from (sub) directory (dir)
  2. Compute sha256 from file (shaNEW)
  3. Check if the filename (shaOLD) is in database

    a) in database: check if shaOLD = shaNEW (if sha is equal: move to dir_inDB; if not: update in DB, rename and move to dir_inDB)

    b) not in database: check if shaOLD = shaNEW (if sha is equal: move to dir_NOTinDB; if not: rename and move to dir_NOTinDB - do NOT add to database)

I am accessing / getting the sourceFile like that:

public static void checkFiles(File file) throws NoSuchAlgorithmException, IOException
{    
    for (File sourceFile : file.listFiles())
    {
        if (sourceFile.isDirectory())
        {
            checkFiles(sourceFile);
        }
        else
        {
            // compute sha, check db, move, rename and so on
        }
    }
}

And the destinationFile as follwos:

File destinationFile = null;
String fileName = sourceFile.getAbsolutePath();
shaNEW = Hash.SHA256(fileName);
char[] c = shaNEW.toCharArray();
String path = sourceFile.getAbsolutePath();
path = path.substring(0, path.lastIndexOf("\\") - 5) + c[0] + c[1] + "\\" + c[2] + c[3] + "\\" + shaNEW;
path = path.replace("dir", "dir_new"); // dir_new = dir_inDB resp. dir_NOTinDB
destinationFile = new File(path);

My problem is: After moving a file I would like to delete the file in the old directory (dir) [but not the (sub) directory itself]. Moving works fine and deleting (but only at first time), too. But from second time onwards the source file is not deleted. I am moving / deleting like that:

FileUtils.copyFile(sourceFile, destinationFile);
sourceFile.delete();

(I do not get any errors or exceptions except own build ones)

I also tried

FileUtils.move(sourceFile, destinationFile);

but then I (sometimes) get an IOException (cannot delete source file)

Does anybody have an idea why sourceFile.delete() only works at the first time?

Thanks in advance and best regards,

Hisushi

EDIT:

I prefer to just move the file (instead of copy and delete) like that: FileUtils.moveFile(sourceFile, destinationFile);

But it throws an IOExeption:

Exception in thread "main" java.io.IOException: Failed to delete original file ...\dir\c [0]c[1]\c[2]c[3]\shaOLD after copy to ...\dir_inDB\c[0]c[1]\c[0]c[1]\shaNEW

at org.apache.commons.io.FileUtils.moveFile(FileUtils.java:2835) at metadatacheck.DatabaseCleanup.checkFiles(DatabaseCleanup.java:264) at metadatacheck.DatabaseCleanup.checkFiles(DatabaseCleanup.java:225) at metadatacheck.DatabaseCleanup.checkFiles(DatabaseCleanup.java:225) at metadatacheck.DatabaseCleanup.main(DatabaseCleanup.java:49)

DatabaseCleanup.java:264: FileUtils.moveFile(sourceFile, destinationFile);

DatabaseCleanup.java:225: checkFiles(sourceFile) (function: see above)

DatabaseCleanup.java:49: checkFiles(dir);

EDIT2:

Now I've tried sourceFile.renameTo(destinationFile); but here the function renameTo() is not executed (I used a simple if-else to check whether renameTo() has been executed or not ).

EDIT3: (hash function)

public static String SHA256(String path) throws FileNotFoundException, NoSuchAlgorithmException, IOException
{
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    FileInputStream fis = new FileInputStream(path);

    byte[] dataBytes = new byte[1024];

    int nread = 0;

    while ((nread = fis.read(dataBytes)) != -1)
    {
        md.update(dataBytes, 0, nread);
    }

    byte[] mdbytes = md.digest();

    StringBuilder sb = new StringBuilder("");
    for (int i = 0; i < mdbytes.length; i++)
    {
        sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
    }

    String sha256 = sb.toString();

    return sha256;
}

Upvotes: 0

Views: 704

Answers (2)

Cristian Sulea
Cristian Sulea

Reputation: 264

Is not enough to just close the stream. For example if an exception is thrown during read of the file, the stream will still be open. I recomend you to use try/catch/finally. I will rewrite a little your method to get the ideea.

public static String SHA256(String path) throws NoSuchAlgorithmException, IOException {

  MessageDigest md = MessageDigest.getInstance("SHA-256");
  FileInputStream fis = null;

  try {

    fis = new FileInputStream(path);

    byte[] dataBytes = new byte[1024];

    int nread = 0;

    while ((nread = fis.read(dataBytes)) != -1) {
      md.update(dataBytes, 0, nread);
    }
  }

  //
  // here you can also log something about exception

  catch (IOException e) {
    throw e;
  }

  //
  // the stream will be closed even in case of unexpected exceptions 

  finally {
    if (fis != null) {
      try {
        fis.close();
      } catch (IOException e) {
        // ignore, nothing to do anymore
      }
    }
  }

  byte[] mdbytes = md.digest();

  StringBuilder sb = new StringBuilder();
  for (int i = 0; i < mdbytes.length; i++) {
    sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
  }

  return sb.toString();
}

Another tip is that StringBuilder doesn't need to be initialized with a string.

Upvotes: 0

Hisushi
Hisushi

Reputation: 67

Just closed the FileInputStream in hashing function like that:

public static String SHA256(String path) throws FileNotFoundException, NoSuchAlgorithmException, IOException
{
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    FileInputStream fis = new FileInputStream(path);

    byte[] dataBytes = new byte[1024];

    int nread = 0;

    while ((nread = fis.read(dataBytes)) != -1)
    {
        md.update(dataBytes, 0, nread);
    }

    byte[] mdbytes = md.digest();

    StringBuilder sb = new StringBuilder("");
    for (int i = 0; i < mdbytes.length; i++)
    {
        sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
    }

    String sha256 = sb.toString();

    fis.close(); // THIS is the point which solved my problem

    return sha256;
}

Thanks to @Cristian Sulea

Upvotes: 0

Related Questions