【问题标题】:file.delete() only works the first timefile.delete() 只在第一次工作
【发布时间】:2014-09-18 08:07:11
【问题描述】:

目前我正在编写一个小程序来检查文件是否在数据库中。此外,我检查数据库中的哈希是否已正确计算(此处:sha256)。文件名是文件中的(旧的并且可能是错误的)sha。

为了更好地理解小型工作流程:

  1. 从(子)目录(dir)获取文件
  2. 从文件计算 sha256 (shaNEW)
  3. 检查文件名(shaOLD)是否在数据库中

    a) 在数据库中:检查是否 shaOLD = shaNEW(如果 sha 相等:移动到 dir_inDB;如果不是:在 DB 中更新,重命名并移动到 dir_inDB)

    b) 不在数据库中:检查 shaOLD = shaNEW(如果 sha 相等:移动到 dir_NOTinDB;如果不是:重命名并移动到 dir_NOTinDB - 不要添加到数据库)

我正在像这样访问/获取 sourceFile:

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
        }
    }
}

destinationFile 如下:

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);

我的问题是:移动文件后,我想删除旧目录(dir)中的文件[但不是(子)目录本身]。移动也可以正常工作并删除(但仅在第一次)。但是从第二次开始源文件不会被删除。我正在这样移动/删除:

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

(除了自己构建的,我没有收到任何错误或异常)

我也试过

FileUtils.move(sourceFile, destinationFile);

但后来我(有时)得到一个 IOException(无法删除源文件)

有人知道为什么sourceFile.delete() 只能在第一次使用吗?

在此先致谢并致以最诚挚的问候,

久志

编辑:

我更喜欢像这样移动文件(而不是复制和删除):FileUtils.moveFile(sourceFile, destinationFile);

但它会抛出一个 IOExeption:

线程 "main" java.io.IOException 中的异常:复制到 .. 后无法删除原始文件 ...\dir\c [0]c[1]\c[2]c[3]\shaOLD .\dir_inDB\c[0]c[1]\c[0]c[1]\shaNEW

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

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

DatabaseCleanup.java:225:checkFiles(sourceFile)(功能:见上文)

DatabaseCleanup.java:49:checkFiles(dir);

EDIT2:

现在我尝试了sourceFile.renameTo(destinationFile);,但这里没有执行函数renameTo()(我使用了一个简单的 if-else 来检查 renameTo() 是否已执行)。

EDIT3:(散列函数)

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;
}

【问题讨论】:

  • 请注意,delete() 在失败时返回 false;它不会抛出异常。关于您的问题,文件是否打开?
  • #copyFile() 方法有什么作用?也许有一个流是打开的,这就解释了为什么只工作一次。
  • 文件甚至没有被触及。我只是获取源文件的名称(sourceFile.getName())和路径(source.File.getAbsolutePath())并将其保存到另一个字符串,检查它是否是一个目录(sourceFile.isDirectory()),并且在结束,尝试删除它。所以我不在任何地方打开文件。 FileUtils.copyFile(source, dest) 复制 - 顾名思义 - 源到 dest(它来自 apache common io)。
  • @immibis 能回答你的问题吗?
  • @CristianSulea 我的哈希函数中有一个流。我在我的问题中编辑了它。你认为这会导致我的问题吗?

标签: java file fileutils


【解决方案1】:

像这样在散列函数中关闭 FileInputStream:

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;
}

感谢@Cristian Sulea

【讨论】:

    【解决方案2】:

    仅仅关闭流是不够的。 例如,如果在读取文件期间抛出异常,流仍将打开。 我建议您使用try/catch/finally。我会重写一点你的方法来得到这个想法。

    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();
    }
    

    另一个提示是StringBuilder 不需要用字符串初始化。

    【讨论】:

    • 非常感谢@Cristian Suela。在这种情况下,我没有考虑过使用 try/catch/finally。感谢 StringBuilder 的提示(我也不知道)。
    猜你喜欢
    • 2018-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    • 1970-01-01
    • 1970-01-01
    • 2017-02-08
    • 2021-04-21
    相关资源
    最近更新 更多