这是 cxuan 的第35篇原创文章 FileDescriptor 是什么 FileDescriptor 顾名思义是文件描述符,FileDescriptor 可以被用来表示开放文件、开放套接字等。 比如用 FileDescriptor 表示文件来说: 当 FileDescriptor 表示文件时,我们可以通俗的将 FileDescriptor 看成是该文件。 若需要通过 FileDescriptor 对该文件进行操作,则需要新创建 FileDescriptor 对应的 FileOutputStream或者是 FileInputStream,再对文件进行操作, 结构 FileDescriptor 有三种输出方式:in、out、error,分别代表 public static final FileDescriptor in = new FileDescriptor public static final FileDescriptor out = new FileDescriptor(1); 一个标准的输出流句柄。
可以使用文件描述符描述任何一个资源对象 就如同Class 之于java语言一样(java中一切都是类,都是一个Class的实例,任何一个类都用Class对象的实例来描述 Java中使用FileDescriptor FileInputStream/FileOutputStream/RandomAccessFile,使用handle来表示底层的文件句柄 对于ServerSocket/Socket,使用fd来表示底层的文件句柄 FileDescriptor FileDescriptor中的三个描述符 FileDescriptor 内置了三个文件描述符 分别是 in out err 类型是FileDescriptor 这是java层面的描述 中一切都是文件): * 标准输入 0 * 标准输出 1 * 标准错误 2 三个描述符,通过调用私有方法 standardStream进行创建初始化 创建一个FileDescriptor
这些资源——文件描述符(FileDescriptor)和句柄(Handle)——是内核管理I/O的核心抽象。 理解FileDescriptor的设计与实现,是洞悉JavaI/O体系乃至JVM如何与操作系统协同工作的关键。 这种设计既保证了FileDescriptor公共API的简洁和安全,又为JDK内部的高效协作提供了可能。 实例注册到FileDescriptor的cleanup字段中。 第五章:标准流与同步操作FileDescriptor类还定义了一些重要的静态常量和方法。
= null) { //省略 ... } //将文件的路径转化为FileDescriptor final File file = new if (file.exists()) { FileInputStream is = new FileInputStream(file); FileDescriptor fd,最终调用到jni的setDataSource(FileDescriptor fd, long offset, long length)方法 android_meida_MediaPlayer.cpp static void android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor ", NULL); return; } int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); ALOGV
在Java中对文件的操作都是通过FileDescriptor,然后JNI调用对应的C代码,在调用系统函数来进行操作,下面会详细分析下具体实现方式。 文件描述符就是Java与操作系统之间关于文件的连接,那么FileDescriptor fd;是在什么时候赋值的呢? 看一下FileDescriptor的实例化过程: 清单4:FileDescriptor实例化过程 public /**/ FileDescriptor() { fd = -1; ,然后应用程序的操作都会通过FileDescriptor映射到对应的socket上。 = FileDescriptor.in)) { /* if fd is shared, the references in FileDescriptor
close(fileDescriptor); return 0; } 5. 移动文件指针 lseek 系统调用用于在文件中移动文件指针的位置。 close(fileDescriptor); return 0; } 6. 关闭文件 close 系统调用用于关闭文件。关闭文件后,与文件描述符相关联的资源将被释放。 I/O 操作... // 关闭文件 close(fileDescriptor); return 0; } 7. close(fileDescriptor); return 0; } 8. 文件和目录操作 Linux 提供了一系列的文件和目录操作函数,可以用于获取和修改文件和目录的属性。 | S_IWUSR); if (fileDescriptor !
PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fileDescriptor fileDescriptor = open( inPathName, O_RDWR, ); if( fileDescriptor < ) { outError = errno if( fstat( fileDescriptor, &statInfo ) ! , statInfo.st_size + appendSize); fsync(fileDescriptor); *outDataPtr = mmap(NULL close( fileDescriptor ); } return outError; } void ProcessFile(const char * inPathName) {
extendsPhantomCleanable<FileDescriptor>:这是关键。 泛型<FileDescriptor>指明了它所监控的对象类型是FileDescriptor。 由于FileDescriptor类的fd(Unix)和handle(Windows)字段是私有的,外部类无法直接访问。 前置检查:只有非空且有效的FileDescriptor才需要注册清理器。捕获资源:通过fdAccess获取到真实的fd和handle值。 构造器打开文件,获得一个有效的FileDescriptor(fdo)。构造器内部调用FileCleanable.register(fdo)。
PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fileDescriptor fileDescriptor = open( inPathName, O_RDWR, 0 ); if( fileDescriptor < 0 ) { outError = if( fstat( fileDescriptor, &statInfo ) ! , statInfo.st_size + appendSize); fsync(fileDescriptor); *outDataPtr = mmap(NULL close( fileDescriptor ); } return outError; } void ProcessFile(const char * inPathName
fileDescriptor1 = rawFileDescriptor.getFileDescriptor(); bis1 = new BufferedInputStream(new FileInputStream fileDescriptor1 = rawFileDescriptor.getFileDescriptor(); bis3 = new BufferedInputStream(new FileInputStream (fileDescriptor1)); byte[] bytes = new byte[bis3.available()]; boolean write3 = renderer1.write fileDescriptor1 = rawFileDescriptor.getFileDescriptor(); bis4 = new BufferedInputStream(new FileInputStream (fileDescriptor1)); short[] shorts = new short[bis4.available()]; boolean write4 = renderer1.write
writeLock.unlock(); } } 这个方法最终会调用IOUtil.write,看下这个方法 Java类sun.nio.ch.IOUtil static int write(FileDescriptor ) throws IOException { return write(fd, src, position, false, -1, nd); } static int write(FileDescriptor Util.offerFirstTemporaryDirectBuffer(bb); } } private static int writeFromNativeBuffer(FileDescriptor nd) throws IOException { return read(fd, dst, position, false, -1, nd); } static int read(FileDescriptor Util.offerFirstTemporaryDirectBuffer(bb); } } private static int readIntoNativeBuffer(FileDescriptor
其实这个思路源自于 gRPC ProtoBuf fileDescriptor[1] var fileDescriptor_308767df5ffe18af = []byte{ // 2522 bytes 0xc2, 0x49, 0x9c, 0xac, 0x53, 0x6c, 0x2b, 0x4b, 0x8c, 0x57, 0xa9, 0xbe, 每次大家更新完 swagger 文档后,都需要手动生成下这个 fileDescriptor $ gzip -c swagger.yaml | xxd -p -c 16 | sed -e 's/../0x&,/g' 但是在多人协作的时候,总有个奇怪的问题:swagger 并没有更新,但是这个 fileDescriptor gzip 已经提供了这样一个选项: $ gzip -n -c swagger.yaml | xxd -p -c 4 | sed -n '2p'00000000 引用链接 [1] gRPC ProtoBuf fileDescriptor
FileInputStream(FileDescriptorfdObj):允许共享一个已存在的FileDescriptor,这在某些高级场景(如重定向标准输入)中非常有用。 创建FileDescriptor:fd=newFileDescriptor();关联自身:fd.attach(this);这一步至关重要,它将当前FileInputStream实例注册为FileDescriptor :FileChannel并非重新打开文件,而是复用了FileInputStream内部的FileDescriptor(fd)。 closeAll会遍历所有通过fd.attach()注册的Closeable对象(即所有共享此FileDescriptor的流),并依次调用它们的close()方法。 安全性:通过FileDescriptor的引用跟踪和FileCleanable的双重保险,最大限度地防止了系统资源泄漏。
des = (FileDescriptor) method.invoke(memoryFile); ParcelFileDescriptor pfd = ParcelFileDescriptor.dup (des); 「进程 B 中通过 binder 拿到 A 进程中准备好的文件描述符,然后直接读取数据:」 FileDescriptor descriptor = pfd.getFileDescriptor SharedMemory create 方法申请了一块匿名共享内存,SharedMemory create 方法中调用了 nCreate native 方法: private static native FileDescriptor //android.system.Os.java public static long mmap(long address, long byteCount, int prot, int flags, FileDescriptor //libcore.io.Linux.java public native long mmap(long address, long byteCount, int prot, int flags, FileDescriptor
* @hide */ public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor 入参args: 转储请求的附加参数 4、shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,String[] args * @hide */ public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor
* @hide */ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ResultReceiver resultReceiverfileDescriptor, long offset) { this.gifAddr = loadFd(fileDescriptor, offset); } /** * 加载gif资源文件 * * @param fileDescriptor * @param offset * @return */ private native long loadFd(FileDescriptor fileDescriptor, long offset); /** * 获取图片的宽 * , jlong offset) { jclass clz = env->GetObjectClass(fileDescriptor); jfieldID jfieldID = env-> GetFieldID(clz, "descriptor", "I"); jint oldFd = env->GetIntField(fileDescriptor, jfieldID);
IOException::class) private fun loadModelFile(activity: Activity): MappedByteBuffer { val fileDescriptor = activity.assets.openFd(MODEL_PATH) val inputStream = FileInputStream(fileDescriptor.fileDescriptor ) val fileChannel = inputStream.channel val startOffset = fileDescriptor.startOffset val declaredLength = fileDescriptor.declaredLength return fileChannel.map(FileChannel.MapMode.READ_ONLY
grpc/metadata" "google.golang.org/grpc/status" "sync" ) var globalProtoMap map[string]*desc.FileDescriptor var IsCached = true var lk sync.RWMutex func init() { globalProtoMap = make(map[string]*desc.FileDescriptor ) } func getProto(path string) *desc.FileDescriptor { lk.Lock() defer lk.Unlock() if IsCached
这个异常通常会在以下场景中发生: 使用FileDescriptor.sync()或FileChannel.force(boolean)方法时,试图将文件缓冲区中的内容强制写入磁盘。 场景示例: FileOutputStream fos = new FileOutputStream("example.txt"); FileDescriptor fd = fos.getFD(); // 三、错误代码示例 以下是一个可能导致java.io.SyncFailedException的错误代码示例: import java.io.FileDescriptor; import java.io.FileOutputStream String[] args) { try (FileOutputStream fos = new FileOutputStream("example.txt")) { FileDescriptor 以下是一个改进后的代码示例: import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException
FileWriter(FileDescriptor fd) 构造与某个文件描述符相关联的 FileWriter 对象。 FileReader(FileDescriptor fd) 在给定从中读取数据的 FileDescriptor 的情况下创建一个新 FileReader。