之前已经提到过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());//输出60
descriptor只是一个id,此id是由native方法返回的,然后java代码通过调用native方法,并传入此id来控制文件流的读写。
参考FileInputStream源码,如果要深入了解文件读写是如何实现的,需要学习IoBridge,Libcore等库。太复杂了,暂时先到这里。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。