Java:如何更新现有的 csv 文件而不创建新文件?

问题描述

我正在写入一个 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 个文件副本。

解决方法

不是它的工作原理。想想磁盘:它有点像一个巨大的单层酒店,拥有数十亿间客房。

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

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

磁盘是一样的。如果您想“就地覆盖”(例如,用磁盘术语将一个奥运选手换成另一个奥运选手:用另一个值更改文件中现有字节的值),这是可能的,您需要使用 java 的 RandomAccessFile 和其他一些更专业的类来执行此操作,这不是一项常见任务。

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

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

假设酒店由磁盘上的一个文件表示,该文件仅在一行中列出奥运选手的姓名,然后在下一行列出下一位奥运选手的姓名,依此类推。

添加一个新的奥运选手,以便系统的其余部分始终获得一致的视图:

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

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

总结:

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...