本文由作者周梁伟授权网易云社区发布。

近日做的项目中涉及到多进程共同读写多个文件的问题,文件名和最后修改时间都是可能会被频繁修改的,因而识别文件的唯一性会产生相当的麻烦,于是专门再学习了一下文件系统对文件的组织管理方式。

一、    文件在文件系统中的组织方式

一块物理磁盘可以被分为若干个分区,分区的初始化操作就是在上面建立文件系统,如ext3,ext4,ntfs或fat32等都是文件系统的概念,还有网络文件系统如NFS等。同块磁盘上的不同分区也可以被指定不同的文件系统,文件系统对文件在磁盘上的数据读写方式做了抽象。一个文件系统中又被分为多个卷(Cylinder Group),每个卷中最主要的部分是inode基路段和数据块段。i-node结构唯一指定了一个文件实例,这个数据结构中包括了inode编号,所有包含的数据块的信息和该inode被引用的计数等。可以这么认为,要唯一识别的一个磁盘上的文件,只需要获得inode-number就可以了。文件或者目录则是存放在数据块中directory block,其中包含了文件名和实体文件的inode-number等信息。文件名是可以随时被改变的,只要其中的inode-number没有发生改变,则指向的就是同一个文件。所以在应用程序中要判断文件是否相同如果依靠filename是不可靠的,只有获取到文件的inode-number才是可靠的。如在log4j这种日志应用中,日志文件的归档方式会使文件名不断发生变化,当前你less到的app.log在下一分钟可能就变成了app.log.1。在这种场景下,程序只能通过获取文件inode-number来识别文件。

二、    文件操作

前面说了文件在磁盘上的存放是以inode-number为唯一id来区分的,在进程打开一个文件读写时,操作系统又会为文件分配一个"指针"来访问文件,而不是直接使用inode-number。这个指针就是FileDescriptor(下面简称FD),FD是一个动态的概念,是进程中调用create后open文件操作是返回的一个Long值,当文件关闭时这个FD也就失效了,所以同一个文件如果被打开两次获取到的FD会是不同的。进程打开文件的情况如下图所示,在进程中维护了一张表记录所有打开的文件,每一条记录表示一个FileDescriptor,每个进程在开始时都默认打开了三个文件,FileDescriptor分别是0,1,2,既stdin, stdout和stderr。FD记录中包含了一张FileTable,记录了文件的状态信息,offset和V-node指针,V-Node指针才真正指向了磁盘上的文件实体。(这里的V-Node是在inode之上抽象出来的概念,因为i-node在不同的文件系统中会有实现上的差异,V-Node是为了统一不同文件系统的接口抽象出来的一层,在Linux中V-Node被称为 FileSystem independent INode ,而INode 称为FileSystem dependent Inode,我们可以简单的理解为 V-Node就是INode)。

当一个文件被多个进程共享读写时,可以看如下图:

这里进程A的fd3和进程B的fd4其实指向的是同一个实体文件,但是这两个进程维护了两张不同的文件表,维护了不同的offset位置。所以如果进程不是采用append方式写文件,两个进程写入的内容可能出现相互覆盖。这里也可能看到虽然FD不同,但是可以指向同一个实体文件,也说明了用FD来判断文件唯一性是不靠谱的。
关于FD和INode,还有关于缓存的重要注意事项。
由于操作系统在接收到文件写请求时可能将写入内容放到缓存中,所以提供了flush和sync等操作来将缓存中的内容强制刷入磁盘。但是这两个操作作用是不同的。
flush会将数据刷入到FileDescriptor中,但是不会刷入Inode
sync/fsync/fdatasync则会强制将FD中的数据刷入Inode中。

三、    Java操作文件的接口

最后需要注意的一点是,虽然在文件的存续期间,inode可以认为是识别该文件的唯一标识,但是文件系统对inode有回收重用的机制,在文件被删除之后,原来的inode可以被分配给新创建的文件,这种情况下,如果一味以inode相同来判定新旧文件是不是同一个文件可能会出现错误;应对这种情况确实也没有更好的办法,一种解决方法是,提取文件中部分内容的MD5或SHA-1这种指纹信息作为标识,以inode+md5是否相同来决定是否是同个文件。

免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐

更多网易技术、产品、运营经验分享请访问网易云社区

相关文章:
【推荐】 初步探索前端性能测试
【推荐】 四步详解数据分析套路
【推荐】 逻辑编程入门--clojure.core.logic

关于文件的INode与Java中的文件操作接口的更多相关文章

  1. Java中删除文件、删除目录及目录下所有文件(转)

    原文链接:Java中删除文件.删除目录及目录下所有文件 知识点:File.delete()用于删除“某个文件或者空目录”!所以要删除某个目录及其中的所有文件和子目录,要进行递归删除,具体代码示例如下: ...

  2. Java中的文件操作

    在使用计算机编程中,常常会用到对于文件的操作,以下是我对于Java中文件的相关内容学习之后的一个总结和在学习过程中遇到的一些问题. 一.什么是文件 对于文件进行操作,首先我们要知道什么是文件.在此之前 ...

  3. Java中读取文件

    Java中读取文件,去除一些分隔符,保存在多维数组里面 public void readFile(String filePath) { File file=new File(filePath); Ar ...

  4. JAVA中获取文件MD5值的四种方法

    JAVA中获取文件MD5值的四种方法其实都很类似,因为核心都是通过JAVA自带的MessageDigest类来实现.获取文件MD5值主要分为三个步骤,第一步获取文件的byte信息,第二步通过Messa ...

  5. Java中获取文件路径

    Java中获取文件路径 1.实例说明 (1)得到 ClassPath的绝对URI路径 Thread.currentThread().getContextClassLoader().getResourc ...

  6. java中常量文件的配置与读取

    java中常量文件的配置与读取: package com.floor.shop.user.util; import java.io.InputStream; import java.io.InputS ...

  7. Java中的文件操作(一)RandomAccessFile

    今天,学到的是java中的文件操作. Java.IO.File Java中操作文件用到RandomAccessFile类,既可以读取文件内容,也可以向文件输出数据,但不同与普通输入/输出流的是Rand ...

  8. java中把文件拷贝到指定目录下最简单几种方法

    java中把文件拷贝到指定目录下最简单几种方法   String savePath = "D:/file";// 文件保存到d盘的file目录下 File savefile = n ...

  9. Java中移动文件或目录的方法盘点

    本文不再更新,可能存在内容过时的情况,实时更新请移步原文地址:Java中移动文件或目录的方法盘点: import org.apache.commons.io.FileUtils; import jav ...

随机推荐

  1. mysqlbateis generator 当遇到tinyint 生成转化bool 解决方法

    当遇到tyint 生成转化bool  类型问题很恶心,记录一下解决方法 一. TinyInt转换规则 JAVA数据类型 和 MYSQL的数据类型转换,要注意tinyInt 类型,且存储长度为1的情况. ...

  2. springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。为了区别不同的异常通常根据异常类型自定义异常类,这里我们创建一个自定义系统异常,如果controller、service、dao抛出此类异常说明是系统预期处理的异常信息。

    springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑. 1.1 异常处理思路 系统中异常包括两类:预期异常和运行时异常RuntimeEx ...

  3. Ubuntu12.04下搭建Java环境

    1.认识需要配置的环境变量 1). PATH: 作用是指定命令搜索路径,打开/etc/environment可以看到PATH变量的值,该变量包含了一系列的路径.那些路径都是一些经常使用的系统命令的目录 ...

  4. asio 广播代码示例

    代码网络收集 修改了一个编译的小问题 客户端 // Client.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include < ...

  5. RSA生成、加密、解密、签名。

    首先,要会生成RSA密码对. https://app.alipay.com/market/document.htm?name=saomazhifu#page-23    (事例中的密钥对好像有问题,最 ...

  6. 记录如何用abd,用电脑输出手机操作信号

    0.http://www.wmzhe.com/soft-39913.html 去这里下载最新版的adb.旧版本很多不好使.一定最新的. 1.用豌豆荚装好驱动 2.开启usb调试.具体方法可以百度到 3 ...

  7. SIM900 AT来电显示开启,一些代码

    /*Note: this code is a demo for how to using gprs shield to send sms message, dial a voice call and ...

  8. UVa 11464 Even Parity (二进制法枚举)

    题意:给你一个n*n的01矩阵,让你把最少的0变成1,使得每个元素的上,下,左,右的元素(如果有的话)之和均为偶数. 析:最好想的的办法就是暴力,就是枚举每个数字是变还是不变,但是...时间复杂度也太 ...

  9. html使用技巧

    line-height: 27px;  /* lineheight和height保持一致就能达到文本垂直居中*/ .top_content li { list-style-image: url(../ ...

  10. ( KMP 求循环节的个数)Power Strings -- poj -- 2406

    链接: http://poj.org/problem?id=2406 Power Strings Time Limit:3000MS     Memory Limit:65536KB     64bi ...