【问题标题】:Most efficient way to check if a file is empty in Java on Windows在 Windows 上的 Java 中检查文件是否为空的最有效方法
【发布时间】:2011-11-03 16:09:20
【问题描述】:

我正在尝试检查日志文件是否为空(意味着没有错误),在 Java 中,在 Windows 上。到目前为止,我已经尝试过使用 2 种方法。

方法一(失败)

FileInputStream fis = new FileInputStream(new File(sLogFilename));  
int iByteCount = fis.read();  
if (iByteCount == -1)  
    System.out.println("NO ERRORS!");
else
    System.out.println("SOME ERRORS!");

方法二(失败)

File logFile = new File(sLogFilename);
if(logFile.length() == 0)
    System.out.println("NO ERRORS!");
else
    System.out.println("SOME ERRORS!");

现在,当日志文件为空(没有内容)但文件大小不为零(2 个字节)时,这两种方法都会失败。

检查文件是否为空的最有效准确的方法是什么?我要求效率,因为我必须循环检查文件大小数千次。

注意:文件大小会徘徊在几到 10 KB 左右!

方法 3(失败)

按照@Cygnusx1 的建议,我也尝试过使用FileReader,但没有成功。这是sn-p,如果有人感兴趣的话。

Reader reader = new FileReader(sLogFilename);
int readSize = reader.read();
if (readSize == -1)
    System.out.println("NO ERRORS!");
else
    System.out.println("SOME ERRORS!");

【问题讨论】:

  • 我不明白文件怎么可以是空的,但仍然有 2 个字节的大小?我已经编写了与您完全相同的代码,并且使用一个空文件,在您的情况下,我得到了预期的结果 NO ERRORS。
  • 好吧,忘了我的评论,看看 BOM 和 unicode。
  • Unicode编码经常使用一个BOM字段作为标识符,占用255字节。我的猜测是,您的空文件是 ANSI 编码的。尝试使用 Unicode 编码。
  • 是的,我看到了,问题:您可以控制此日志文件的创建吗?你能把它的编码改成UTF-8吗?它会解决你的问题。
  • 我已经考虑过了。但在我的具体情况下,遗憾的是,没有。

标签: java file logging file-io filesystems


【解决方案1】:

检查文件的第一行是否为空:

BufferedReader br = new BufferedReader(new FileReader("path_to_some_file"));     
if (br.readLine() == null) {
    System.out.println("No errors, and file empty");
}

【讨论】:

  • 好吧,我想我会使用这种方法,因为它有效。你能说这是最有效的方法吗?
  • 更新:此方法也不起作用。当我使用readLine() 时,它会返回这些垃圾字符-ÿþ。现在我很困惑。
  • 如果输入文件是 ANSI 编码的,则此方法确实有效。将此标记为答案。
  • 是我遗漏了什么还是没有 file.readLine() 方法?
  • @w25r java.io.File.readLine() 不存在,Victor 指的是使用 BufferedReader.readLine() 的示例。我已经更新了答案,这样它就不会再令人困惑了。
【解决方案2】:

为什么不直接使用:

File file = new File("test.txt");

if (file.length() == 0) {
    // file empty
} else {
    // not empty
}

有什么问题吗?

【讨论】:

  • 这不适用于 Unicode 文件。在我的原始帖子中检查 方法 2
  • 它还返回 long file.length() 方法
  • @GPX 抱歉上课迟到了。当你说一个unicode文件可以为空但有字节时,你指的是this吗?
【解决方案3】:

这是根据 Anwar Shaikh 的评论改进 Saik0 的答案,即太大的文件(超出可用内存)会引发异常:

使用 Apache Commons FileUtils

private void printEmptyFileName(final File file) throws IOException {
    /*Arbitrary big-ish number that definitely is not an empty file*/
    int limit = 4096;
    if(file.length < limit && FileUtils.readFileToString(file).trim().isEmpty()) {
        System.out.println("File is empty: " + file.getName());
    }        
}

【讨论】:

    【解决方案4】:

    您可以选择尝试使用 FileReader 方法,但现在可能还不是放弃的时候。 如果 BOM 字段为您破坏,请尝试在 stackoverflow 上发布的解决方案。

    Byte order mark screws up file reading in Java

    【讨论】:

    • 虽然理论上这可以回答这个问题,it would be preferable 在这里包含答案的基本部分,并提供链接以供参考。
    【解决方案5】:

    另一种方法是(使用Apache CommonsFileUtils)-

    private void printEmptyFileName(final File file) throws IOException {
        if (FileUtils.readFileToString(file).trim().isEmpty()) {
            System.out.println("File is empty: " + file.getName());
        }        
    }
    

    【讨论】:

    • readFileToString(..) 方法如果文件很大且可用内存不足,将给出异常“Java heap space error”。
    【解决方案6】:

    现在,当日志文件为空(没有内容)但文件大小不为零(2 个字节)时,这两种方法都会失败。

    其实我想你会发现文件不是空的。相反,我认为您会发现这两个字符是 CR 和 NL;即文件包含一行是空的。

    如果你想测试一个文件是空的还是有一个空行,那么一个简单、相对有效的方法是:

    try (BufferedReader br = new BufferedReader(FileReader(fileName))) {
        String line = br.readLine();
        if (line == null || 
            (line.length() == 0 && br.readLine() == null)) {
            System.out.println("NO ERRORS!");
        } else {
            System.out.println("SOME ERRORS!");
        }
    }
    

    我们可以更有效地做到这一点吗?可能。这取决于您处理这三种不同情况的频率:

    • 一个完全空的文件
    • 由一个空行组成的文件
    • 包含非空行或多行的文件。

    使用Files.length() 和/或只读取前两个字节可能会做得更好。但是,问题包括:

    • 如果您同时测试文件大小并读取前几个字节,那么您将进行 2 次系统调用。
    • 实际线路终止顺序可能是 CR、NL 或 CR NL,具体取决于平台。 (我知道您说这是针对 Windows 的,但如果您需要移植您的应用程序会发生什么?或者如果有人向您发送非 Windows 文件?)
    • 最好避免设置流/阅读器堆栈,但文件的字符编码可以将 CR 和 NL 映射到字节 0x0d0x0a 以外的其他内容。 (例如……UTF-16)
    • 然后是一些 Windows 实用程序将 BOM 标记放入 UTF-8 编码文件的恼人习惯。 (这甚至会弄乱上面的简单版本!)

    所有这些都意味着最有效的解决方案将相当复杂。

    【讨论】:

      【解决方案7】:

      试试FileReader,这个阅读器是用来读取字符流的,而FileInputStream是用来读取原始数据的。

      来自 Javadoc:

      FileReader 用于读取字符流。用于阅读 原始字节流,请考虑使用 FileInputStream。

      由于您想读取日志文件,FileReader 是使用 IMO 的类。

      【讨论】:

      • 是的,我用这两种方法进行了测试,它们的工作方式相同。最后,我的建议仍然有效,但它并没有解决 unicode BOM 问题。查看 Farmor 的答案以及指向有关此问题的另一个答案的链接。
      【解决方案8】:
      String line = br.readLine();
      String[] splitted = line.split("anySplitCharacter");
      if(splitted.length == 0)
          //file is empty
      else
          //file is not empty
      

      我的文本文件也有同样的问题。虽然它是空的,但 readLine 方法返回的值不是 null。因此,我尝试将其值分配给我用来访问数据的拆分属性的字符串数组。它确实对我有用。试试这个,告诉我它是否也适合你。

      【讨论】:

      • 为什么不检查line.isEmpty()
      • 这是因为 br.readLine 将返回一个非空值,因为在创建文件时,虽然它看起来是空的,但实际上并不是空的。我不确定其中已经有哪些字符,但文件不是空的,即使它看起来好像是。
      • 你的意思是什么?如果isEmpty()看起来为空,你认为isEmpty()会返回true吗?
      • 不,我并不是说如果 isEmpty() 看起来是空的,它就会返回 true。我们都知道 String 是一个字符数组,我们也知道如果 String 的长度为零,isEmpty() 返回 true,但是如果我们打开文件,我所说的这些隐藏的垃圾字符在文件中是不可见的但是它们在那里并且加起来是 String 的长度,因此 isEmpty() 在这里使用的方法不合适。
      • 为什么拆分操作会不同?
      【解决方案9】:

      我结合了两种最佳解决方案来涵盖所有可能性:

      File file = new File(fileName);
      BufferedReader br = new BufferedReader(new FileReader(file));     
      if (br.readLine() == null && file.length() == 0)
      {
          System.out.println("No errors, and file empty");
      }                
      else
      {
          System.out.println("File contains something");
      }
      

      【讨论】:

        【解决方案10】:

        盗自http://www.coderanch.com/t/279224/Streams/java/Checking-empty-file

        FileInputStream fis = new FileInputStream(new File("file_name"));  
        int b = fis.read();  
        if (b == -1)  
        {  
          System.out.println("!!File " + file_name + " emty!!");  
        }  
        

        更新:我的第一个答案为时过早并且包含错​​误。

        【讨论】:

        • 我不应该在同一页上考虑 Rob 的想法吗?
        • 是的,抱歉我的第一篇文章为时过早:(
        【解决方案11】:

        您的第一个 sn-p 的想法是正确的。您可能打算检查iByteCount == -1:文件是否至少一个字节:

        if (iByteCount == -1)  
            System.out.println("NO ERRORS!");
        else
            System.out.println("SOME ERRORS!");
        

        【讨论】:

        • 这很尴尬!但是尝试一下,我有一个空文件(绝对是空的 - 没有空格,没有新行) - 但字节数是 255 个字节。我的猜测是,这可能是因为 Unicode 的 BOM 字段。所以这个方法对我不起作用。
        【解决方案12】:

        我认为最好的方法是使用file.length == 0

        有时第一行可能是空的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-12-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-04
          • 2017-09-15
          • 2012-04-04
          相关资源
          最近更新 更多