写入 csv 文件时意外的行数

Unexpected amount of lines when writing to a csv file

我的应用程序的一部分按以下方式将数据写入 .csv 文件:

public class ExampleWriter {

    public static final int COUNT = 10_000;
    public static final String FILE = "test.csv";

    public static void main(String[] args) throws Exception {
        try (OutputStream os = new FileOutputStream(FILE)){         
            os.write(239);
            os.write(187);
            os.write(191);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));         
            for (int i = 0; i < COUNT; i++) {               
                writer.write(Integer.toString(i));
                writer.newLine();               
            }           
        } catch (IOException e) {                       
            e.printStackTrace();
        }

        System.out.println(checkLineCount(COUNT, new File(FILE)));
    }

    public static String checkLineCount(int expectedLineCount, File file) throws Exception {
        BufferedReader expectedReader = new BufferedReader(new FileReader(file));
        try {
            int lineCount = 0;
            while (expectedReader.readLine() != null) {
                lineCount++;
            }
            if (expectedLineCount == lineCount) {
                return "correct";       
            } else {
                return "incorrect"; 
            }
        }
        finally {
            expectedReader.close();
        }
    }
}

文件将在 excel 中打开,数据中包含各种语言。 os.write 部分用于为文件添加字节顺序标记作为前缀,以启用所有类型的字符。

不知何故,文件中的行数与循环中的计数不匹配,我不知道是怎么回事。对于我在这里做错的任何帮助,将不胜感激。

COUNT为1时,main()中的代码会写一个两行的文件,一行数据加上后面的空行。然后你调用 checkLineCount(COUNT, file) 期望它会 return 1 但它 returns 2 因为文件实际上有两行。 因此,如果您希望计数器匹配,则不得在最后一行之后写新行。

您只需在打开文件进行输入和计数之前刷新并关闭输出流(强制 fsync)。尝试添加:

writer.flush();
writer.close();

在你的 try 块中。在 main 方法中的 for 循环之后。

您没有刷新流,请参阅 oracle docs 了解更多信息 上面写着

Flushes this output stream and forces any buffered output bytes to be written out. The general contract of flush is that calling it is an indication that, if any bytes previously written have been buffered by the implementation of the output stream, such bytes should immediately be written to their intended destination. If the intended destination of this stream is an abstraction provided by the underlying operating system, for example a file, then flushing the stream guarantees only that bytes previously written to the stream are passed to the operating system for writing; it does not guarantee that they are actually written to a physical device such as a disk drive.

The flush method of OutputStream does nothing.

您需要刷新并关闭流。有2种方法

  1. 手动调用 close() 和 flush()。

  2. 尝试使用资源

正如我从您的代码中看到的那样,您已经实现了 try with resource 并且 BufferedReader class 还实现了 Closeable、Flushable,因此请按照以下代码使用代码

public static void main(String[] args) throws Exception {
        try (OutputStream os = new FileOutputStream(FILE); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))){         
            os.write(239);
            os.write(187);
            os.write(191);

            for (int i = 0; i < COUNT; i++) {               
                writer.write(Integer.toString(i));
                writer.newLine();               
            }          
        } catch (IOException e) {                       
            e.printStackTrace();
        }

        System.out.println(checkLineCount(COUNT, new File(FILE)));
    }

(作为旁注)。

请注意,使用 BOM 是可选的,并且(在许多情况下)会降低文件的可移植性(因为并非所有消费应用程序都能很好地处理它)。它 保证文件具有公布的字符编码。所以我建议删除 BOM。使用 Excel 时,只需 select 文件并选择 UTF-8 作为编码。

(作为另一个旁注)。

请注意,以您现在的方式编写 CSV 文件确实是一种糟糕的做法。 CSV 并不像乍一看那么容易!所以,除非你 真的 知道你在做什么(所以要知道所有 CSV 怪癖),否则请使用库!