1. 程式人生 > >關於Android中的檔案讀寫(jniGetFDFromFileDescriptor)

關於Android中的檔案讀寫(jniGetFDFromFileDescriptor)

Java中常用的檔案讀寫的兩個類:

1.FileInputStream/FileOutputStream(FileReader/FileWriter)

2.RandomFileAccess

FileInputSteamFileOutputStream繼承於InputStreamOutputStreamFileReaderFileWriter繼承於ReaderWriter,它們的底層實現原理其實是樣的,區別在於一個前者用於位元組型資料流讀寫,後者用於unicode文字流讀寫

RandomFileAccess是一個獨立的檔案讀寫類,它與InputStreamOutputStream不同之處在於它更傾向與隨機檔案讀寫,類似

C語言fopenfreadfseekfwritefflushfclose的封裝。

eg.FileOutputStream

File file2 = new File("FileOut.txt");

if(file2 == null)

{

            dbgOutput("ERR","File 2 Can't make");

            return;

}

FileOutputStream fos = new FileOutputStream(file2); //此處才會建立檔案出來

if(fos == null)

{                                 

        dbgOutput("ERR","File 2 Output stream can't make");

        return;

}

byte [] words = {'a','b','c','d','e'};

fos.write(words);

fos.flush();

fos.close();

eg.RandomAccessFile

RandomAccessFile rf = new RandomAccessFile("rtest.dat", "rw"); 

        for (int i = 0; i < 10; i++) { 

            //寫入基本型別

double資料 

            rf.writeDouble(i * 1.414); 

        } 

        rf.close(); 

        rf = new RandomAccessFile("rtest.dat", "rw"); 

        //直接將檔案指標移到第5double資料後面 

        rf.seek(5 * 8); 

        //覆蓋第6double資料 

        rf.writeDouble(47.0001); 

        rf.close(); 

        rf = new RandomAccessFile("rtest.dat", "r"); 

        for (int i = 0; i < 10; i++) { 

            System.out.println("Value " + i + ": " + rf.readDouble()); 

        } 

        rf.close(); 

Android Java 檔案讀寫IO類的具體實現的程式碼在libcore中實現,原理也是通過JNI的方式實現的,對於

FileInputStreamFileOutStream類,繼承於InputStreamOutputStream類,但InputStreamOutputStream只聲明瞭抽象的readwrite介面,如:

@ \libcore\luni\src\main\java\java\io\InputStream.java

@ \libcore\luni\src\main\java\java\io\OutputStream.java

public abstract int read() throws IOException;

public abstract void write(int oneByte) throws IOException;

具體的實現還是在FileInputStreamFileOutputStream中重寫的,其中實現的程式碼如下:

@ \libcore\luni\src\main\java\java\io\FileInputStream.java

@ \libcore\luni\src\main\java\java\io\FileOutputStream.java

    @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {

        return IoBridge.read(fd, buffer, byteOffset, byteCount);

    }

    public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException {

        IoBridge.write(fd, buffer, byteOffset, byteCount);

    }

其中呼叫了IoBridge類實現,readwrite方法都是靜態方法,實現的程式碼如下:

@ \android\libcore\luni\src\main\java\libcore\io\IoBridge.java

read方法

   /**

     * java.io thinks that a read at EOF is an error and should return -1, contrary to traditional

     * Unix practice where you'd read until you got 0 bytes (and any future read would return -1).

     */

    public static int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {

        Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount);

        if (byteCount == 0) {

            return 0;

        }

        try {

            int readCount = Libcore.os.read(fd, bytes, byteOffset, byteCount);

            if (readCount == 0) {

                return -1;

            }

            return readCount;

        } catch (ErrnoException errnoException) {

            if (errnoException.errno == EAGAIN) {

                // We return 0 rather than throw if we try to read from an empty non-blocking pipe.

                return 0;

            }

            throw errnoException.rethrowAsIOException();

        }

    }

@ \android\libcore\luni\src\main\java\libcore\io\IoBridge.java

write方法:

/**

     * java.io always writes every byte it's asked to, or fails with an error. (That is, unlike

     * Unix it never just writes as many bytes as happens to be convenient.)

     */

    public static void write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {

        Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount);

        if (byteCount == 0) {

            return;

        }

        try {

            while (byteCount > 0) {

                int bytesWritten = Libcore.os.write(fd, bytes, byteOffset, byteCount);

                byteCount -= bytesWritten;

                byteOffset += bytesWritten;

            }

        } catch (ErrnoException errnoException) {

            throw errnoException.rethrowAsIOException();

        }

    }

LibCore類只有Os這一個物件:

\libcore\luni\src\main\java\libcore\io\LibCore.java

package libcore.io;

public final class Libcore {

    private Libcore() { }

    public static Os os = new BlockGuardOs(new Posix());

}

Os物件是一系列系統呼叫的抽象介面,從LibCore.java中可以看出它是通過Posix這個類實現的,這個類中讀寫的實現如下:

@\libcore\luni\src\main\java\libcore\io\Posix.java

    public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException {

        if (buffer.isDirect()) {

            return readBytes(fd, buffer, buffer.position(), buffer.remaining());

        } else {

            return readBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + buffer.position(), buffer.remaining());

        }

    }

    public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException {

        // This indirection isn't strictly necessary, but ensures that our public interface is type safe.

        return readBytes(fd, bytes, byteOffset, byteCount);

    }

    private native int readBytes(FileDescriptor fd, Object buffer, int offset, int byteCount) throws ErrnoException;

  public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException {

        if (buffer.isDirect()) {

            return writeBytes(fd, buffer, buffer.position(), buffer.remaining());

        } else {

            return writeBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + buffer.position(), buffer.remaining());

        }

    }

    public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException {

        // This indirection isn't strictly necessary, but ensures that our public interface is type safe.

        return writeBytes(fd, bytes, byteOffset, byteCount);

    }

    private native int writeBytes(FileDescriptor fd, Object buffer, int offset, int byteCount) throws ErrnoException;

最終是通過native呼叫來實現的,

@\libcore\luni\src\main\native\libcore_io_Posix.cpp

static jint Posix_writeBytes(JNIEnv* env, jobject, jobject javaFd, jbyteArray javaBytes, jint byteOffset, jint byteCount) {

    ScopedBytesRO bytes(env, javaBytes);

    if (bytes.get() == NULL) {

        return -1;

    }

    int fd = jniGetFDFromFileDescriptor(env, javaFd);

    return throwIfMinusOne(env, "write", TEMP_FAILURE_RETRY(write(fd, bytes.get() + byteOffset, byteCount)));

}

static jint Posix_readBytes(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount) {

    ScopedBytesRW bytes(env, javaBytes);

    if (bytes.get() == NULL) {

        return -1;

    }

    int fd = jniGetFDFromFileDescriptor(env, javaFd);

    return throwIfMinusOne(env, "read", TEMP_FAILURE_RETRY(read(fd, bytes.get() + byteOffset, byteCount)));

}

對於RandomAccessFile的呼叫過程:

@\libcore\luni\src\main\java\java\io\RandomAccessFile.java

    public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {

        return IoBridge.read(fd, buffer, byteOffset, byteCount);

    }

    public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException {

        IoBridge.write(fd, buffer, byteOffset, byteCount);

        // if we are in "rws" mode, attempt to sync file+metadata

        if (syncMetadata) {

            fd.sync();

        }

    }

雖然RandomAccessFilejava中是與FileInputStreamFileOutputStream設計得完全不同的類,但其底層實現還是一樣的。

相關推薦

關於Android檔案jniGetFDFromFileDescriptor

Java中常用的檔案讀寫的兩個類: 1.FileInputStream/FileOutputStream(FileReader/FileWriter) 2.RandomFileAccess FileInputSteam和FileOutputStream繼承於InputStream和OutputStre

Android檔案輸入流和輸出流操作總結附原始碼

Android中檔案讀寫操作 1. Android中檔案讀寫的原理: (1).所有檔案的儲存都是位元組的儲存。 (2).在磁碟上保留的並不是檔案的字元而是先把字元編碼成位元組,再儲存這些位元組到磁碟。 (3).在讀取檔案(

MPI檔案1

使用MPI的檔案讀寫函式時,檔案需為二進位制檔案,可以使用程式碼自己進行格式轉換 示例程式碼: //將儲存三個數的文字檔案轉換為二進位制檔案 int r,c,m; FILE *fp = fopen(filein, "r"); fscanf(fp, "%d", &r

python檔案從file1讀出資料並計算,然後將結果寫入到file2

要求新建兩個檔案,file1、file2,要求開啟file1檔案,分別對每一行數字進行求和,並將每一行的結果寫在file2中。 file1: 20 30 40 20 52 63 52 52 85 52 8 456 522 25 36 85 96 74 程式原始碼: 定義一個求和函式

AndroidAndroid TXT檔案

轉載網址:http://blog.csdn.net/wirelessqa/article/details/7807762 package com.wirelessqa.helper; import java.io.FileInputStream; import java

C 檔案二進位制檔案

  我們將介紹 C 程式設計師如何建立、開啟、關閉文字檔案或二進位制檔案。 一個檔案,無論它是文字檔案還是二進位制檔案,都是代表了一系列的位元組。C 語言不僅提供了訪問頂層的函式,也提供了底層(OS)呼叫來處理儲存裝置上的檔案。本章將講解檔案管理的重要呼叫。 開啟檔案 您可

C語言檔案輸入輸出重定向

  freopen("D:\\test.txt","r",stdin);//檔案讀入 輸入重定向 freopen("D:\\test.txt","w",stdout);//檔案寫入 輸出重定向 檔案讀入(輸入重定向) freopen ( " D:\\test.txt

二進位制檔案視訊

問題及程式碼: (1)二進位制檔案寫入 #include<iostream> #include<fstream> #include<cstdlib> using n

Python JSON檔案 縮排、排序、格式化

寫檔案,格式化 indent: 縮排(一般填4,縮排4格); sort_keys: 是否排序(預設False–不排序) def write_info(file_name, file

[轉]C#對文本文件的

eve nextline reader 操作系統 為我 reat ini toe http 原網頁:http://www.cnblogs.com/infly123/archive/2013/05/18/3085872.html 計算機在最初只支持ASCII編碼,但是後來為了

windows下測試磁盤Iometer

測試磁盤讀寫速度 iometer測試磁盤讀寫速度 參考鏈接:http://hll142475.blog.163.com/blog/static/62138201151113835216/http://blog.csdn.net/yuesichiu/article/details/8499787http

Android-3】Android的任務棧Task

集合 情況下 清除 bsp 生命周期方法 任務棧 保存 sin 也會 一、Android任務棧 概述:Android中的任務棧其實就是Activity的集合,在Android中退出程序的時候必須把任務棧中的所有Activity清除出棧,此時才能安全的完全的退出程序, 任務棧

python之文件的2

import 文件讀寫 哈哈 進入 imp std 技術 都是 繼續 小R昨天因為在研究weblogic的漏洞就沒來得及學習python(好吧,這都是借口,懶了,大家可不能像我這樣。要堅持每天都學)。 這個進度是有點慢呀。哎呀,沒事沒事,我還年輕,才20歲。 哈哈,玩

Android的對話方塊AlertDialog

建立android中分體式對話方塊需要四個步驟: 第一:獲得AlertDialog的靜態內部類Builder物件,有該類建立對話方塊。 第二:通過Builder物件設定對話方塊的標題,按鈕UI及將要響應的事件。、 第三:呼叫Builder的Create()方法建立對對話方塊 第四

python檔案

讀寫檔案是最常見的IO操作。Python內建了讀寫檔案的函式,用法和C是相容的。 讀寫檔案前,我們先必須瞭解一下,在磁碟上讀寫檔案的功能都是由作業系統提供的,現代作業系統不允許普通的程式直接操作磁碟,所以,讀寫檔案就是請求作業系統開啟一個檔案物件(通常稱為檔案描述符),然後,通過作業系統提供的介面從

Opencv開發筆記五:畫素的

一、講講什麼是畫素 畫素是指由影象的小方格即所謂的畫素(pixel)組成的,這些小方塊都有一個明確的位置和被分配的色彩數值,這些小方塊內放的數和所放的位置據決定了影象在某個位置所顯示的顏色,比如某一塊區域放的都是數字0(255),則該片區域會顯示出黑色(白色),可以將畫素視

shp系列——利用C++進行shp檔案建立

之前介紹了shp檔案、dbf檔案和shx檔案的的讀取,接下來將分別介紹它們的建立過程。一般來說,讀和寫的一一對應的,寫出的檔案就是為了儲存資料供以後讀取的。寫的檔案要符合shapefile的標準。之前讀取的時候使用的函式是fread,寫的函式對應為fwrite,檔案為二進位制流檔案。 建議本部落格和之前sh

shp系列——利用C++進行Dbf檔案建立

上一篇介紹了shp檔案的建立,接下來介紹dbf的建立。 推薦結合讀取dbf的部落格一起看! 推薦結合讀取dbf的部落格一起看! 推薦結合讀取dbf的部落格一起看!     1.Dbf標頭檔案的建立 Dbf標頭檔案的結構如下: 記錄項陣列說明: 欄位型別說明:

shp系列——利用C++進行Shx檔案建立

之前介紹了Shp檔案和Dbf的寫(建立),最後來介紹一下Shx檔案的寫(建立)。Shx檔案是三者之中最簡單的一個,原因有兩個:第一是Shx檔案的標頭檔案與Shp檔案的標頭檔案幾乎一樣(除了FileLength);第二是Shx檔案的主體只有兩個記錄項,分別是Offset和ContentLength。 推薦結合

嵌入式 Linux 對記憶體的直接devmem

https://blog.csdn.net/xy010902100449/article/details/47028497【摘要】 在Linux開發中著實用到的除錯工具並不是很多。devmem的方式是提供給驅動開發人員,在應用層能夠偵測記憶體地址中的資料變化,以此來檢測驅動中對記憶體或者相關配置的正確性驗證