V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
albin504
V2EX  ›  Java

Java 一行行读大文件,读的过程中删除文件,竟然还能继续读剩下的?

  •  
  •   albin504 · 2023-04-26 12:37:52 +08:00 · 3627 次点击
    这是一个创建于 606 天前的主题,其中的信息可能已经有所发展或是发生改变。
    package io;
    
    import java.io.*;
    import java.util.concurrent.TimeUnit;
    
    public class InodeTest {
        public static void main(String[] args) throws IOException, InterruptedException {
            BufferedReader reader = new BufferedReader(new FileReader("/Downloads/2020.zip"), 2);
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
                TimeUnit.MILLISECONDS.sleep(10);
            }
        }
    }
    
    

    这个文件有几百兆,程序执行一会儿,我删除 2020.zip 这个文件(从回收站也删了),竟然还能继续读到剩下的文件,为什么?

    难道 java 一次性把文件内容都加载到进程中了吗?

    26 条回复    2023-06-02 10:40:58 +08:00
    zjsxwc
        1
    zjsxwc  
       2023-04-26 12:39:46 +08:00
    文件系统了解下
    pluto1
        2
    pluto1  
       2023-04-26 12:47:12 +08:00 via iPhone
    你看看文件系统剩余空间,应该是没释放的,因为还有 fd 没关掉,其实这时候底层的数据是还在的,等所有 fd 全部关了才会释放
    zjp
        3
    zjp  
       2023-04-26 12:47:18 +08:00 via Android   ❤️ 4
    看文件路径应该是 Linux ,只有在所有打开此文件的进程都关闭此文件后,文件才会实际删除
    https://zhuanlan.zhihu.com/p/25650525
    chenzhongxiang
        4
    chenzhongxiang  
       2023-04-26 12:48:04 +08:00
    win 应该删不掉,提示文件被占用。linux 能出现你描述的现象。不过在你删的是你看到的一个“快捷方式”。不过 zip 文件怎么一行一行的读? zip 是二进制文件。
    documentzhangx66
        5
    documentzhangx66  
       2023-04-26 13:30:27 +08:00   ❤️ 1
    建议楼主,有时间,先把计算机基础知识学一下。

    不然,零基础学 Java ,就算再努力,也可能变成 CURD Boy 。
    moyechen
        6
    moyechen  
       2023-04-26 13:44:08 +08:00
    你用 echo > /Downloads/2020.zip 应该就不能继续读了😄
    msg7086
        7
    msg7086  
       2023-04-26 13:44:48 +08:00
    删除文件不影响文件内的数据,除非是粉碎文件。
    bugmakerxs
        8
    bugmakerxs  
       2023-04-26 13:52:12 +08:00
    句柄还在,占用的空间不会被释放。
    RollingTruck
        9
    RollingTruck  
       2023-04-26 13:55:19 +08:00
    windows 下试了下, 中间应该有一层读缓存,
    在 bufferedReader 读取到第一行后, 手动修改文件内第三行的内容,
    使 bufferedReader 继续读取, 读取到第三行时, 仍旧读取到了修改前的内容
    OpenJdk
        10
    OpenJdk  
       2023-04-26 13:57:21 +08:00
    不会一次加载到内存里面,应该是更文件系统有关。
    RollingTruck
        11
    RollingTruck  
       2023-04-26 13:59:23 +08:00
    ```java
    try {
    Scanner sc = new Scanner(System.in);
    BufferedReader fileReader = new BufferedReader(new FileReader("path to file"));
    System.out.println(fileReader.readLine());
    sc.nextLine();
    System.out.println(fileReader.readLine());
    sc.nextLine();
    System.out.println(fileReader.readLine());
    sc.nextLine();
    System.out.println(fileReader.readLine());
    sc.nextLine();
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }

    ```
    hez2010
        12
    hez2010  
       2023-04-26 14:06:38 +08:00
    你用的是 BufferedReader ,之所以叫做 Buffered 就是因为提前会对一部分或者全部内容做缓冲啊。
    optional
        13
    optional  
       2023-04-26 14:13:09 +08:00 via iPhone
    linux 的文件机制。
    churchmice
        14
    churchmice  
       2023-04-26 14:29:14 +08:00
    linux 下面把 shell bang 改成
    #!/bin/rm
    可以起到既删除文件又继续运行里面命令的效果,真乃杀人越货,居家旅行的必备良药
    Worldispow
        15
    Worldispow  
       2023-04-26 14:43:26 +08:00
    不但能继续读,记得还有个 lsof 还是命令,还能把文件找回
    albin504
        16
    albin504  
    OP
       2023-04-26 14:52:30 +08:00
    非常感谢。

    unlink() deletes a name from the filesystem. If that name was
    the last link to a file and no processes have the file open, the
    file is deleted and the space it was using is made available for
    reuse.

    If the name was the last link to a file but any processes still
    have the file open, the file will remain in existence until the
    last file descriptor referring to it is closed.

    删除一个文件时,如果有进程打开了该文件,文件实际上并不会删除,直到该文件相关的描述符都关了
    albin504
        17
    albin504  
    OP
       2023-04-26 14:53:51 +08:00
    @hez2010 Buffer size 设置的很小。2 字节
    albin504
        18
    albin504  
    OP
       2023-04-26 14:54:46 +08:00
    @moyechen 测试了,还能继续读
    albin504
        19
    albin504  
    OP
       2023-04-26 14:56:11 +08:00
    @pluto1 正解。感谢
    liudaolunhuibl
        20
    liudaolunhuibl  
       2023-04-26 15:05:53 +08:00
    new FileReader 会获取到一个文件描述符,fd ,文件被申请到了 fd 说明正在被正在运行的进程使用,而 linux 和 Uninx 中如果文件正在被使用了即使运行了 rm 也不会真正被删除:
    https://access.redhat.com/solutions/2316

    https://stackoverflow.com/questions/71198721/bufferedreader-still-reads-from-a-file-even-after-the-file-have-been-deleted
    si
        21
    si  
       2023-04-26 15:06:20 +08:00
    文件还在使用的时候不会释放空间。
    我遇到过服务器的硬盘空间满了,但现有的文件大小又对不上。
    执行`lsof |grep deleted` 发现 MySQL 有大量显示 deleted 状态的文件,最后重启 MySQL 就释放了。
    albin504
        22
    albin504  
    OP
       2023-04-26 15:55:06 +08:00
    @si 我们业务上也遇到到类似问题,你这一提醒,我意识到我们当时也是这么回事。
    springwood
        23
    springwood  
       2023-04-27 07:49:22 +08:00
    任何一种编程语言好像都是这样的
    xuanbg
        24
    xuanbg  
       2023-04-27 09:22:10 +08:00
    删除文件相当于把你家的住址从地址簿上删掉了,但你家没搬走,我还是可以直接上门的。
    moyechen
        25
    moyechen  
       2023-06-02 09:59:46 +08:00
    @albin504 #18
    看了一下,应该是 FileReader 会将整个文件内容加载到内存中,然后进行读取操作。所以 echo 清空文件也是不行的
    moyechen
        26
    moyechen  
       2023-06-02 10:40:58 +08:00
    @moyechen #25 我专门下了个 jdk ,echo 后,读取停止了的😅
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   881 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 20:38 · PVG 04:38 · LAX 12:38 · JFK 15:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.