FileDescriptor到底实现了那些功能
之前已经提到过FileDescriptor,利用FileDescriptor我可以方便的实现播放资源包中的视频文件,而不用先解压出来。
这么神奇的一个类,究竟实现了哪些功能呢?
看了看源码:
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.io;
import libcore.io.ErrnoException;
import libcore.io.Libcore;
import static libcore.io.OsConstants.*;
/**
* Wraps a Unix file descriptor. It's possible to get the file descriptor used by some
* classes (such as {@link FileInputStream}, {@link FileOutputStream},
* and {@link RandomAccessFile}), and then create new streams that point to the same
* file descriptor.
*/
public final class FileDescriptor {
/**
* Corresponds to {@code stdin}.
*/
public static final FileDescriptor in = new FileDescriptor();
/**
* Corresponds to {@code stdout}.
*/
public static final FileDescriptor out = new FileDescriptor();
/**
* Corresponds to {@code stderr}.
*/
public static final FileDescriptor err = new FileDescriptor();
/**
* The Unix file descriptor backing this FileDescriptor.
* A value of -1 indicates that this FileDescriptor is invalid.
*/
private int descriptor = -1;
static {
in.descriptor = STDIN_FILENO;
out.descriptor = STDOUT_FILENO;
err.descriptor = STDERR_FILENO;
}
/**
* Constructs a new invalid FileDescriptor.
*/
public FileDescriptor() {
}
/**
* Ensures that data which is buffered within the underlying implementation
* is written out to the appropriate device before returning.
*/
public void sync() throws SyncFailedException {
try {
Libcore.os.fsync(this);
} catch (ErrnoException errnoException) {
SyncFailedException sfe = new SyncFailedException(errnoException.getMessage());
sfe.initCause(errnoException);
throw sfe;
}
}
/**
* Tests whether this {@code FileDescriptor} is valid.
*/
public boolean valid() {
return descriptor != -1;
}
/**
* Returns the int fd. It's highly unlikely you should be calling this. Please discuss
* your needs with a libcore maintainer before using this method.
* @hide internal use only
*/
public final int getInt$() {
return descriptor;
}
/**
* Sets the int fd. It's highly unlikely you should be calling this. Please discuss
* your needs with a libcore maintainer before using this method.
* @hide internal use only
*/
public final void setInt$(int fd) {
this.descriptor = fd;
}
@Override public String toString() {
return "FileDescriptor[" + descriptor + "]";
}
}有3个静态变量in,out,err,都是FileDescriptor类型的。
有个descriptor属性,int类型,私有,又实现了该属性的getter和setter,还是隐藏的,只供框架内调用。
valid方法,还是和descriptor有关,判断descriptor是不是等于-1 。
有一个sync方法,不了解,没看懂。
toString就不用多说了。
我们看,FileDescriptor其实就只有一个int类型的descriptor属性。
那么descriptor究竟是什么,又是如何实现各种文件的读写的呢?
利用之前学到的反射,我们可以读到descriptor的值(刚学的知识就用上了)。
先写一个方法利用反射来读取并输出FileDescriptor的descriptor值。代码如下:
private void shuchuDescriptor(FileDescriptor fd){
Class<FileDescriptor> c = FileDescriptor.class;
Method method;
try {
method = c.getMethod("getInt$");
method.setAccessible(true);
Object obj = method.invoke(fd, null);
Log.d("hanyeah", "descriptor="+obj);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}然后测试
//直接new一个FileDescriptor
shuchuDescriptor(new FileDescriptor());//输出-1
shuchuDescriptor(FileDescriptor.in);//输出0
shuchuDescriptor(FileDescriptor.out);//输出1
shuchuDescriptor(FileDescriptor.err);//输出2
for(int i=0;i<10;i++){
FileInputStream fStreami = new FileInputStream(Environment.getExternalStorageDirectory()+"/test.mp4");
shuchuDescriptor(fStreami.getFD());//输出50+i
}
FileInputStream fStream2 = new FileInputStream(Environment.getExternalStorageDirectory()+"/test.jpg");
shuchuDescriptor(fStream2.getFD());//输出60descriptor只是一个id,此id是由native方法返回的,然后java代码通过调用native方法,并传入此id来控制文件流的读写。
参考FileInputStream源码,如果要深入了解文件读写是如何实现的,需要学习IoBridge,Libcore等库。太复杂了,暂时先到这里。