0

我正在写入一个 csv 文件,然后再更新它。但随着。我的更新代码,生成了一个新的相同文件。下面是我的代码,我想知道如何在不创建新文件的情况下进行更新。


public void updateFile(List<String> fileNames, String key, String value) throws IOException {
        for (String file: fileNames) {

            InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8);
            CSVReader reader = new CSVReader(inputStreamReader);

            String[] header = reader.readNext();
            int columnNum = Arrays.asList(header).indexOf(key);

            List<String[]> data = reader.readAll();
            for (String[] row : data) {
                row[columnNum] = value;
            }
            reader.close();

            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(feedFile), StandardCharsets.UTF_8);
            CSVWriter writer = new CSVWriter(outputStreamWriter);
            writer.writeNext(header);
            writer.writeAll(data);
            writer.flush();
            writer.close();
        }
    }

通过新文件,我的意思是,现在创建了 2 个具有不同时间戳的文件副本。

4

1 回答 1

2

不是它是如何工作的。想象一个磁盘:它有点像一个拥有数十亿间客房的巨型单层酒店。

现在想象一下,在这家酒店里,所有的奥运选手都签到了,他们都在连续的房间里,按国家和名字排序。

然后一位新的奥运选手迟到了。你不能只是“更新”你的酒店,给这个奥运选手一个房间。诺诺,你必须告诉大约一半的奥运选手将一个房间向右移动,腾出空间。

磁盘是一样的。如果您想“就地覆盖”(例如,用磁盘术语将一个奥林匹亚人换成另一个奥林匹亚人:用另一个值更改文件中现有字节的值),这是可能的,您需要使用 javaRandomAccessFile和其他一些更专业的类来做到这一点,这不是一项常见的任务。

但是对于绝大多数文件更新,您无法按照固定大小进行更新,然后就磁盘而言,“就地更新”的概念已经不存在了。

但是,您可以做的是这个有点常见的任务,它确保在该硬件上运行的其他进程始终观察到一致的数据:

假设酒店由磁盘上的一个文件表示,该文件仅在一行中列出了奥林匹克运动员的名字,然后在下一行列出了下一个奥林匹克运动员的名字,依此类推。

添加一个新的 olymian 以便系统的其余部分始终获得一致的视图:

  • 创建一个名为 eg 的新文件olympians.txt.new.123981329183(该数字只是随机生成以避免冲突),然后开始从旧文件复制数据。
  • 在复制操作期间,“修复”文件,如在正确的位置插入新的奥林匹亚。
  • 完成后关闭文件,然后Files.move()ATOMIC_MOVE标志一起使用,以要求 java 要求操作系统以原子方式重命名olympians.txt.new.123981329183olympians.txt:任何olympians.txt打开的进程要么打开旧文件,要么打开新文件,无论他们得到了哪一个,他们总是得到完整的视图;看不到新文件,但只能看到一半,或者什么都看不到。

在该模型中,就硬盘而言,您有 2 个完全不同的文件,但路径(文件名)只是指向磁盘上某个位置的指针,仅此而已。就在该硬件上运行的软件而言,只有一个文件,称为olympians.txt,如果您打开它,它总是完整且一致的。当新的奥运选手出现时,最终打开该文件将包含他们的名字,并且它会在正确的位置。

概括:

  • 如果您想在不更改任何大小的情况下替换值,这在技术上是可行的,但不是原子方式,并且需要专门的 JDK 类,例如RandomAccessFile.
  • 如果要删除或添加数据(更改大小),就硬盘而言,您想要的是不可能的。
  • 但是,您可以让它看起来只有一个文件始终一致并且不时更新,复制文件并使用java.nio.file.Files'smove方法将其旋转回正确的名称,确保使用StandardCopyOperation.ATOMIC_MOVE标志.
于 2021-07-20T21:25:37.080 回答