关于文件的INode与Java中的文件操作接口
本文由作者周梁伟授权网易云社区发布。
近日做的项目中涉及到多进程共同读写多个文件的问题,文件名和最后修改时间都是可能会被频繁修改的,因而识别文件的唯一性会产生相当的麻烦,于是专门再学习了一下文件系统对文件的组织管理方式。
一、 文件在文件系统中的组织方式
一块物理磁盘可以被分为若干个分区,分区的初始化操作就是在上面建立文件系统,如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中的文件操作接口的更多相关文章
- Java中删除文件、删除目录及目录下所有文件(转)
原文链接:Java中删除文件.删除目录及目录下所有文件 知识点:File.delete()用于删除“某个文件或者空目录”!所以要删除某个目录及其中的所有文件和子目录,要进行递归删除,具体代码示例如下: ...
- Java中的文件操作
在使用计算机编程中,常常会用到对于文件的操作,以下是我对于Java中文件的相关内容学习之后的一个总结和在学习过程中遇到的一些问题. 一.什么是文件 对于文件进行操作,首先我们要知道什么是文件.在此之前 ...
- Java中读取文件
Java中读取文件,去除一些分隔符,保存在多维数组里面 public void readFile(String filePath) { File file=new File(filePath); Ar ...
- JAVA中获取文件MD5值的四种方法
JAVA中获取文件MD5值的四种方法其实都很类似,因为核心都是通过JAVA自带的MessageDigest类来实现.获取文件MD5值主要分为三个步骤,第一步获取文件的byte信息,第二步通过Messa ...
- Java中获取文件路径
Java中获取文件路径 1.实例说明 (1)得到 ClassPath的绝对URI路径 Thread.currentThread().getContextClassLoader().getResourc ...
- java中常量文件的配置与读取
java中常量文件的配置与读取: package com.floor.shop.user.util; import java.io.InputStream; import java.io.InputS ...
- Java中的文件操作(一)RandomAccessFile
今天,学到的是java中的文件操作. Java.IO.File Java中操作文件用到RandomAccessFile类,既可以读取文件内容,也可以向文件输出数据,但不同与普通输入/输出流的是Rand ...
- java中把文件拷贝到指定目录下最简单几种方法
java中把文件拷贝到指定目录下最简单几种方法 String savePath = "D:/file";// 文件保存到d盘的file目录下 File savefile = n ...
- Java中移动文件或目录的方法盘点
本文不再更新,可能存在内容过时的情况,实时更新请移步原文地址:Java中移动文件或目录的方法盘点: import org.apache.commons.io.FileUtils; import jav ...
随机推荐
- 配置静态IP
网卡配置静态IP地址编辑文件/etc/network/interfaces:sudo vi /etc/network/interfaces并用下面的行来替换有关eth0的行:# The primary ...
- 创建和修改主键 (SQL)
添加主键, ALTER TABLE [表名:OrderInfo] Add PRIMARY KEY ([列名:ProductID, UserID...]) 多个列则是组合主键 删除主键, ALTER ...
- MacOs安装mysql与修改root密码
1.下载安装包 http://www.mysql.com/downloads/ 找到如下内容下载 mysql-5.7.21-1-macos10.13-x86_64.dmg下载地址是 https://c ...
- Linux安装和配置Vim7.4
一.简介 Vim是一个类似于Vi的文本编辑器,不过在Vi的基础上增加了很多新的特性,Vim普遍被推崇为类Vi编辑器中最好的一个,事实上真正的劲敌来自Emacs的不同变体.1999 年Emacs被选为L ...
- Codeforces 689B. Mike and Shortcuts SPFA/搜索
B. Mike and Shortcuts time limit per test: 3 seconds memory limit per test: 256 megabytes input: sta ...
- makefile all
all:udps udpc udps:udpserv.c gcc -Wall -o udps udpserv.cudpc:udpclient.c gcc -Wall -o udpc udp ...
- Socket-IO 系列(一)Linux 网络 IO 模型
Socket-IO 系列(一)Linux 网络 IO 模型 一.基本概念 在正式开始讲 Linux IO 模型前,先介绍 5 个基本概念. 1.1 用户空间与内核空间 现在操作系统都是采用虚拟存储器, ...
- android的 Base64
byte[] key=Base64.decode("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4".getBytes(), Base64.DEFAULT); ...
- sigint sigterm 有什么区别啊
SIGHUP 终止进程 终端线路挂断SIGINT 终止进程 中断进程SIGQUIT 建立CORE文件终止进程,并且生成core文件SIGILL 建立CORE文件 ...
- 【commons-httpclient】Java中HttpClient工具访问Web请求
注意jar包是: HttpClient工具使用 HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的.最新的.功能丰富的支持 HTTP 协议的客户端编程 ...