一。FileInputStream屬性:
/* File Descriptor - handle to the open file */
private final FileDescriptor fd;
/*用來標識輸入流的狀態*/
private final String path; //檔案的路徑資訊
private FileChannel channel = null;
private final Object closeLock = new Object();//關閉時的同步鎖
private volatile boolean closed = false;
二。FileInputStream過載了3個構造方法。能夠通過以下三種方式初始輸入流:
- public FileInputStream(String name) throws FileNotFoundException;
:以路徑的方式初始一個輸入流。其內部呼叫的是以下的構造方法
public FileInputStream(String name) throws FileNotFoundException { this(name != null ? new File(name) : null);//當name不為空,就生成一個File物件 作為FileInputStream(File file)建構函式的引數 }
- public FileInputStream(File file) throws FileNotFoundException;
:以File例項的方法初始一個輸入流
原始碼為:
1 public FileInputStream(File file) throws FileNotFoundException { 2 String name = (file != null ? file.getPath() : null); 3 SecurityManager security = System.getSecurityManager(); 4 if (security != null) { 5 security.checkRead(name); 6 } 7 if (name == null) { 8 throw new NullPointerException(); 9 } 10 if (file.isInvalid()) { 11 throw new FileNotFoundException("Invalid file path"); 12 } 13 fd = new FileDescriptor(); 14 fd.attach(this); 15 path = name; 16 open(name); 17 }
構造方法內部解析:
SecurityManager security = System.getSecurityManager();
其中 當執行未知的Java程式的時候,該程式可能有惡意程式碼(刪除系統檔案、重啟系統等),為了防止執行惡意程式碼對系統產生影響,需要對執行的程式碼的許可權進行控制,這時候就要啟用Java安全管理器(SecurityManager)。
1.預設的安全管理器配置檔案是 $JAVA_HOME/jre/lib/security/java.policy,即當未指定配置檔案時,將會使用該配置。
使用之前需要啟動SecurityManager,啟動有兩種方式:引數方式、編碼方式
啟動程式的時候通過附加引數啟動安全管理器:
-Djava.security.manager
若要同時指定配置檔案的位置那麼示例如下:
-Djava.security.manager -Djava.security.policy="E:/java.policy"
"="表示這個策略檔案將和預設的策略檔案一同發揮作用; "=="表示只使用指定的策略檔案 。如 -Djava.security.policy==E:/temp/test1.policy或者 -Djava.security.policy=bin/com/test/test1.policy
編碼方式(不建議):
System.setSecurityManager(new SecurityManager());
引數方式啟動:
儲存後在執行security就不為null了 ,走進security.checkRead(name); 拋錯(使用了預設配置檔案)
這時候解決方式:(1)關閉安全管理器;(2)賦予該程式讀取檔案許可權
開啟管理器配置檔案新增:
grant { permission java.io.FilePermission "C:\\Study\\*", "read"; permission java.io.FilePermission "C:\\Study\\2401.jpg_wh1200.jpg", "write"; };
給程式新增檔案讀許可權
其中 permission java.io.FilePermission "C:\Study\2401.jpg_wh1200.jpg", "read"; 一個反斜槓是錯誤的
許可權項中出現的專案必須按指定順序出現(permission,permission_class_name,”target_name”,”action” 和 signedBy “signer_names”)。分號表示項終止。
大小寫對於識別符號(permission、signedBy、codeBase 等)來說並不重要,但對於 permission_class_name 或作為值傳遞過來的字串而言就很重要了。
有關 Windows 系統上檔案路徑規範的注意事項
請注意:在指定 java.io.FilePermission 時,”target_name” 是檔案路徑。在 Windows 系統上,無論何時在字串中(而不是在 codeBase URL 中)直接指定檔案路徑,路徑中都需要兩個反斜槓來代表一個實際的反斜槓;
- public FileInputStream(FileDescriptor fdObj);
:以FileDescriptor例項初始一個輸入流(FileDescriptor是一個檔案描寫敘述符
FileDescriptor:檔案描述符類的例項用作表示開啟檔案,開放套接字或其他位元組源或信宿的底層機器特定結構的不透明控制程式碼。 檔案描述符的主要實際用途是建立一個FileInputStream
或FileOutputStream
來包含它。
三。FileInputStream方法
int |
available()
返回從此輸入流中可以讀取(或跳過)的剩餘位元組數的估計值,而不會被下一次呼叫此輸入流的方法阻塞。
|
|
void |
close()
關閉此檔案輸入流並釋放與流相關聯的任何系統資源。
|
|
protected void |
finalize()
確保當這個檔案輸入流的
close 方法沒有更多的引用時被呼叫。 |
|
FileChannel |
getChannel()
返回與此檔案輸入流相關聯的唯一的
FileChannel 物件。 |
關於FileChannel可以參考以上部落格 |
FileDescriptor |
getFD()
返回表示與此
FileInputStream 正在使用的檔案系統中實際檔案的連線的 FileDescriptor 物件。 |
|
int |
read()
從該輸入流讀取一個位元組的資料。
|
|
int |
read(byte[] b)
從該輸入流讀取最多
b.length 個位元組的資料為位元組陣列。 |
|
int |
read(byte[] b, int off, int len)
從該輸入流讀取最多
len 位元組的資料為位元組陣列。 |
|
long |
skip(long n)
跳過並從輸入流中丟棄
n 位元組的資料。 |
available():要一次讀取多個位元組時,經常用到InputStream.available()方法,這個方法可以在讀寫操作前先得知資料流裡有多少個位元組可以讀取。需要注意的是,如果這個方法用在從本地檔案讀取資料時,一般不會遇到問題,但如果是用於網路操作,就經常會遇到一些麻煩。比如,Socket通訊時,對方明明發來了1000個位元組,但是自己的程式呼叫available()方法卻只得到900,或者100,甚至是0,感覺有點莫名其妙,怎麼也找不到原因。其實,這是因為網路通訊往往是間斷性的,一串位元組往往分幾批進行傳送。本地程式呼叫available()方法有時得到0,這可能是對方還沒有響應,也可能是對方已經響應了,但是資料還沒有送達本地。對方傳送了1000個位元組給你,也許分成3批到達,這你就要呼叫3次available()方法才能將資料總數全部得到。能否使用取決於實現了InputStream這個抽象類的具體子類中有沒有實現available這個方法。如果實現了那麼就可以取得大小,如果沒有實現那麼就獲取不到。例如FileInputStream就實現了available方法,那麼就可以用new byte[in.available()];這種方式。但是,網路程式設計的時候Socket中取到的InputStream,就沒有實現這個方法,那麼就不可以使用這種方式建立陣列。
public static void main(String[] args) { String name="C:\\Study\\2401.jpg_wh1200.jpg"; // inputStream(); /*Person per=new Student(); per.doSomething();*/ FileInputStream fis=null; try { File file=new File(name); fis=new FileInputStream(file); int available = fis.available(); System.out.println(available); long n=500000; fis.skip(n); int available2 = fis.available(); System.out.println("available2 is "+available2 ); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); }finally { if(fis!= null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
控制檯執行結果:
532598
available2 is 32598
read()方法:從此輸入流中每次只讀取讀取一個資料位元組。如果沒有輸入可用,則此方法將阻塞。 指定者:類 InputStream 中的 read 返回:下一個資料位元組;如果已到達檔案末尾,則返回 -1。
1、此方法是從輸入流中讀取一個資料的位元組,效率會非常低,更好的方法是用InputStream.read(byte[] b)或者InputStream.read(byte[] b,int off,int len)方法,一次讀取多個位元組。通俗點講,即每呼叫一次read方法,從FileInputStream中讀取一個位元組。
2、返回下一個資料位元組,如果已達到檔案末尾,返回-1,這點除看難以理解,通過程式碼測試理解不難。
3、如果沒有輸入可用,則此方法將阻塞。這不用多解釋,大家在學習的時候,用到的Scannner sc = new Scanner(System.in);其中System.in就是InputStream(為什麼?不明白的,請到System.class查閱in是個什麼東西!!),大家都深有體會,執行到此句程式碼時,將等待使用者輸入 摘自 JAVA-FileInputStream之read方法 部落格
本地測試程式碼如下:
public class Test1 { private static String name="C:\\Study\\output.txt"; @Test public void Test1() { FileInputStream file=null; int i=0; //呼叫read()次數 try { file=new FileInputStream(name); int read =0; System.out.println("available is :"+file.available());// while(read != -1) {返回從此輸入流中可以讀取(或跳過)的剩餘位元組數的估計值 該檔案輸入流值為:68 read= file.read(); i++; System.out.println(read+" and i="+i); } } catch (FileNotFoundException e) { e.printStackTrace(); }catch (IOException e) { e.printStackTrace(); }finally { if( file != null ) { try { file.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
控制檯輸出結果為:
available is :68 228 and i=1 189 and i=2 160 and i=3 229 and i=4 165 and i=5 189 and i=6 239 and i=7 188 and i=8 140 and i=9 230 and i=10 136 and i=11 145 and i=12 230 and i=13 152 and i=14 175 and i=15 229 and i=16 188 and i=17 160 and i=18 228 and i=19 184 and i=20 137 and i=21 32 and i=22 230 and i=23 136 and i=24 145 and i=25 228 and i=26 187 and i=27 138 and i=28 229 and i=29 164 and i=30 169 and i=31 229 and i=32 190 and i=33 136 and i=34 229 and i=35 188 and i=36 128 and i=37 229 and i=38 191 and i=39 131 and i=40 229 and i=41 146 and i=42 140 and i=43 228 and i=44 189 and i=45 160 and i=46 231 and i=47 186 and i=48 166 and i=49 228 and i=50 188 and i=51 154 and i=52 32 and i=53 232 and i=54 175 and i=55 183 and i=56 229 and i=57 164 and i=58 154 and i=59 229 and i=60 164 and i=61 154 and i=62 230 and i=63 140 and i=64 135 and i=65 230 and i=66 149 and i=67 153 and i=68 -1 and i=69
- private static native void initIDs();
- private native void close0() throws IOException;
- private native void open0(String name) throws FileNotFoundException; :開啟檔案
- private native int read0() throws IOException; :讀取一個位元組
- private native int readBytes(byte b[], int off, int len) throws IOException; :讀取指定位元組數
- public native long skip(long n) throws IOException; 丟棄指定位元組,下次讀取時,從丟棄後的位置開始讀取
- public native int available() throws IOException;
FileInputStream內部,有幾個native型別的方法,用於呼叫底層語言來完整對於檔案系統的操作:
FileInputStream流類內部提供了一種對於檔案操作的機制,可是因為Java語言的侷限,FileInputStream須要通過native方法呼叫底層語言實現。