在結構體與指針中 , 我們了解到結構體與java中的類相似 , 也是一種自定義類型數據結構 , 也學習了結構的各種用法 , 以及簡單的應用 。
在編寫應用程序的時候 , 文件IO操作是不可避免的 , 小到日志本地化收集 , 大到數據格式化存儲 , 都需要使用文件IO , 來操作文件流進行數據處理 。在使用java開發的時候 , 我們有File類和FileReader,FileWriter類來搭配使用 , 也有FileInputStream,FileOutputStream和BufferedInputStream,BufferedOutputStream金牌組合 。使得java中的文件IO很方便 , 下面我們就來看看簡單的java文件IO示例:
// 讀取文件中的字符 private static void readString() throws Exception{ File _file = new File("e:"+separetor+"a.txt") ; if (!_file.exists()) { boolean createStatuts = _file.createNewFile() ; if (createStatuts) { System.out.println("創建了一個新文件 ,並且創建成功了"); }else { System.out.println("創建新文件失敗"); } } // 創建輸入流 InputStream fileInputStream = new FileInputStream(_file) ; byte[] bytes = new byte[1024] ; int len = -1; StringBuffer buffer = new StringBuffer() ; while ((len = fileInputStream.read(bytes)) != -1) { buffer.append(new String(bytes,0,len)) ; } // 關閉輸入流 fileInputStream.close() ; System.out.println(buffer.toString()); } // 將字符串寫入文件 private static void writeString() throws Exception{ File _file = new File("e:"+separetor+"a.txt") ; if (!_file.exists()) { boolean createStatuts = _file.createNewFile() ; if (createStatuts) { System.out.println("創建了一個新文件 ,並且創建成功了"); }else { System.out.println("創建新文件失敗"); } } // 創建輸出流 OutputStream fileOutputStream = new FileOutputStream(_file) ; String info = "《op 青空 pure rouge 君吻》《君吻 その目に映るもの piano》" ; fileOutputStream.write(info.getBytes()) ; // 關閉輸出流 fileOutputStream.close() ; }
1.創建一個File對象(需要操作的文件)
2.構建輸入輸出流
3.創建緩沖區 , 緩存讀寫數據 (將流數據讀入到內存或寫入到磁盤)
3.關閉流 (關閉文件流)
語言都是相通的 , 在C語言中文件IO的操作也是如上述幾步 , 下面我們就一起來看看:
/*讀取文本文件*/ void readTextFile() { char* path = "C:\\Users\\Zeno\\Documents\\Visual Studio 2015\\Projects\\Hello_C\\Hello_C\\StructPointer.c"; // 打開文件 FILE* fp = fopen(path, "r"); if (fp == NULL) { printf("打開文件失敗\n"); return; } // 字符緩沖區 , 每次讀一個字符串 , 都會緩存到字符數組中 char buffer[1024]; while (fgets(buffer, 1024, fp)) { printf("%s", buffer); } // 關閉文件流 fclose(fp); /*寫入文本文件*/ void writeTextFile() { char* path = "E:\\document\\write.txt"; char* content = "如果 愛情是一場花火 ,一閃即逝的花火,我也要去追求\n如果 愛情是一場花火 ,一閃即逝的花火,我也要去追求\n"; // 打開文件 /* 打開只寫文件,若文件存在則文件長度清為0,即該文件內容會消失。若文件不存在則建立該文件。 */ FILE* fp = fopen(path, "w"); if (fp == NULL) { printf("打開文件失敗\n"); return; } // 寫入文件 fputs(content, fp); // 關閉文件流 fclose(fp); } }
首先使用fopen函數得到一個文件指針 , 操作符r為讀取文件流 , 構建了一個buffer數據緩沖區 , 通過fgets函數循環讀取文件數據 , fclose函數關閉文件流 。在操作文件IO的時候 , 最重要的函數 , 莫過於fopen函數了 , 首先我們來看一下fopen函數的定義:
_ACRTIMP FILE* __cdecl fopen( _In_z_ char const* _FileName, _In_z_ char const* _Mode );
我們發現fopen函數 , 需要傳入文件全路徑名稱 , 還有一個_Mode , 這個是文件操作模式 , C語言中文件操作主要依靠操作模式來辨別是輸入流還是輸出流的 。
下面列舉一些常用的操作模式:
mode有下列幾種形態字符串: r 打開只讀文件,該文件必須存在。 r+ 打開可讀寫的文件,該文件必須存在。 w 打開只寫文件,若文件存在則文件長度清為0,即該文件內容會消失。若文件不存在則建立該文件。 w+ 打開可讀寫文件,若文件存在則文件長度清為零,即該文件內容會消失。若文件不存在則建立該文件。 a 以附加的方式打開只寫文件。若文件不存在,則會建立該文件,如果文件存在,寫入的數據會被加到文件尾,即文件原先的內容會被保留。 a+ 以附加方式打開可讀寫的文件。若文件不存在,則會建立該文件,如果文件存在,寫入的數據會被加到文件尾後,即文件原先的內容會被保留。
值得注意的是 , 上述操作模式是針對文本文件的 , 如果要操作二進制文件 , 則需要在上述操作符後面加上b , 如rb,wb,ab , 等等 。
不論是文本文件的操作還是字符文件的操作 , 都是 , 打開文件 , 創建緩沖區 , 讀寫文件 。
/*讀寫二進制文件 -- 復制文件*/ void fileCopy() { char* currentPath = "E:\\android_pdf\\研磨設計模式.pdf"; char* destPath = "E:\\android_pdf\\研磨設計模式_new.pdf"; // 打開文件 FILE* currentFile_P = fopen(currentPath, "rb"); FILE* destFile_P = fopen(destPath, "wb"); // 先讀取再寫入 int buffer[1024]; // 數據緩沖區 int len; // 每次讀取數據的長度 while ((len = fread(buffer,sizeof(int),1024,currentFile_P)) != EOF) { // 將緩沖區裡的內容寫入到文件中 fwrite(buffer, sizeof(int), len, destFile_P); } // 關閉流 fclose(destFile_P); fclose(currentFile_P); }
讀寫二進制和讀寫文本文件沒多少區別 , 最大的區別就是fopen函數中的模式的不同 , 文本文件是r,w , 二進制文件是rb,wb 。
了解了文件IO的基本操作 , 我們使用文件IO流寫一個加密解密的小程序。我們知道 , 所有的文件都是以二進制存儲的 , 我們看的文本文件, 圖片文件 , 視頻文件 , 都是以二進制存儲在磁盤上的 , 那麼 , 我們可以將文件讀取出來 , 進行二進制運算 , 就可以將文件加密解密了 。下面我們通過^異或運算來進行文件的加密解密 , 異或運算的規則如下:
0 ^ 1 得 1 1 ^ 1 得 0 0 ^ 0 得 0 1 ^ 0 得 1
相同為0 不同為1 , 例如 , 我們將4這個數加密 , 異或的數是5 , 下面我們來看看運算:
4的二進制是:0100 5的二進制是:0101 異或運算結果(加密):4 ^ 5 == 0001 異或運算結果(解密): 0001 ^ 0101 == 0100 由上述可見 , ^一次為加密 , 再^一次就是解密
代碼示例如下:
/*加密文件*/ void encryptFile() { // 待加密文件路徑 char* normal_path = "E:\\poto\\xj.jpg"; // 加密後文件路徑 char* encrypt_path = "E:\\poto\\xj_encrypt.jpg"; //打開文件 FILE* normal_fp = fopen(normal_path, "rb"); FILE* encrypt_fp = fopen(encrypt_path, "wb"); // 讀文件 int buffer; while ((buffer = fgetc(normal_fp)) != EOF) { // 寫入文件 fputc(buffer ^ 8, encrypt_fp); } printf("文件加密成功\n"); // 關閉流 fclose(encrypt_fp); fclose(normal_fp); }
/*文件解密*/ void decryptFile() { // 加密文件路徑 char* encrypt_path = "E:\\poto\\xj_encrypt.jpg"; // 解密文件路徑 char* decrypt_path = "E:\\poto\\xj_deencrypt.jpg"; // 打開文件 FILE* encrypt_fp = fopen(encrypt_path, "rb"); FILE* decrypt_fp = fopen(decrypt_path, "wb"); // 讀取文件 int buffer; while ((buffer = fgetc(encrypt_fp)) != EOF) { // 寫文件 fputc(buffer ^ 8, decrypt_fp); } printf("文件解密成功\n"); // 關閉流 fclose(decrypt_fp); fclose(encrypt_fp); }
了解了文件加密的原理 , 我們也可以推導出其他形式的加密 , 如帶密碼的文件加密解密 , 混合文件加密解密等等 。
不知不覺C語言基礎系列已經寫了快十篇了 , 也快告一段落了 , 有了這些基礎知識 , 我們就可以去分析分析jni.h頭文件了 , 下一個系列是jni開發系列 , 我們學C語言就是為了能和java打交道 , 那麼下個系列我們就來學習C與java的橋梁 , jni (Java Native Interface)技術 。