1. 程式人生 > >檔案讀寫中的inputStream和outputStream

檔案讀寫中的inputStream和outputStream

InputStream(輸入流)用來讀取資料

OutputStream(輸出流)用來寫出資料

public int read();//從此輸入流中讀取一個數據位元組

public int read(byte[] b);//從此輸入流中將最多b.length個位元組資料讀取到byte陣列中

public int read(byte b[]) throws IOException {
    Object traceContext = IoTrace.fileReadBegin(path);
    int bytesRead = 0;
    try {
        bytesRead = readBytes(b, 0, b.length);
    } finally {
        IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead);
    }
    return bytesRead;
}

public int read(byte[] b,int off,int len);//從此輸入流中將最多 len 個位元組的資料讀入一個 byte 陣列中。off:目標陣列 b 中的起始偏移量。

public int read(byte b[], int off, int len) throws IOException {
    Object traceContext = IoTrace.fileReadBegin(path);
    int bytesRead = 0;
    try {
        bytesRead = readBytes(b, off, len);
    } finally {
        IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead);
    }
    return bytesRead;
}
package fileDo;

import java.io.FileInputStream;

/**
 * @auther **
 * @date 7/31/2018 3:02 PM
 */
public class FileReadStream {
    public static void main(String[] args){
        String content = null;
        try{
            int size = 0;
            //定義一個位元組緩衝區,該緩衝區的大小根據需要來定義
            byte[] buffer = new byte[1024];
            FileInputStream fis = new FileInputStream("d:/read.txt");
            //迴圈讀取檔案中的資料
            while((size = fis.read(buffer)) != -1){
                content = new String(buffer, 0, size);
                System.out.println(content);
            }
            fis.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
為什麼上文中會有size = fis.read(buffer)) != -1呢?
因為原始碼中有寫明如果沒有資料可以讀的話就返回一個-1給回來,所以如果siz = -1時就代表已經讀完啦
* @return     the total number of bytes read into the buffer, or
*             <code>-1</code> if there is no more data because the end of
*             the file has been reached.

OutputStream相關如下:

//建立一個向指定 File 物件表示的檔案中寫入資料的檔案輸出流。

public FileOutputStream(File file);

//建立一個向指定 File 物件表示的檔案中寫入資料的檔案輸出流。如果第二個引數為 true,則將位元組寫入檔案末尾處,而不是寫入檔案開始處。

public FileOutputStream(File file,boolean append);

//建立一個向具有指定名稱的檔案中寫入資料的輸出檔案流。

public FileOutputStream(String name);

//建立一個向具有指定 name 的檔案中寫入資料的輸出檔案流。如果第二個引數為 true,則將位元組寫入檔案末尾處,而不是寫入檔案開始處。

public FileOutputStream(String name,boolean append);

以上有個比較關鍵的就是boolean append,這個傳參如果是true,原文中的內容可以繼續保留,如果為false,原文將會被清空,寫入新的內容進去。並不是從開頭開始寫且原有內容後移哦。

常用方法如下:

//向檔案中寫入一個位元組大小的資料

public void write(int b);

//將 b.length 個位元組從指定 byte 陣列寫入此檔案輸出流中。

public void write(byte[] b);

//指定 byte 陣列中從偏移量 off 開始的 len 個位元組寫入此檔案輸出流。

public void write(byte[] b,int off,int len);

package fileDo;

import javax.imageio.IIOException;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @auther ***
 * @date 8/1/2018 10:45 AM
 */
public class FileWriteStream {
    public static void main(String[] args){
        String context = "測試寫入檔案流";
        try{
            FileOutputStream fos = new FileOutputStream("d:/read.txt");
            fos.write(context.getBytes());
            fos.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

從上文得到思考,這個時候每次執行其實都會覆蓋之前寫入的內容,那麼怎麼持續性的寫入呢?

其實就是append引數寫進去就好了

如下:

FileOutputStream fos = new FileOutputStream("d:/read.txt",true);

這樣每次都會往後面繼續寫了。

再思考一下,怎麼每次寫的時候不是從之前的末尾開始寫,而是每次換行寫入呢?

如下:

fos.write(context.getBytes());
fos.write("\r\n".getBytes());

再加入一個寫入\r\n的操作就好啦

藉助inputStream和outputStream實現檔案的複製

package fileDo;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @auther ***
 * @date 8/1/2018 11:13 AM
 */
public class FileInOutCopy {
    public static void main(String[] args) throws IOException {
        byte[] buffer = new byte[1024];
        int size = 0;
        FileInputStream fis = new FileInputStream("d:/read.txt");
        FileOutputStream fos = new FileOutputStream("d:/write.txt",true);
        String context = new String();
        while ((size = fis.read(buffer)) != -1){
            fos.write(buffer,0,size);
        }
        fis.close();
        fos.close();
    }
}

這裡我們需要思考一下:

fos.write(buffer,0,size);

這裡的意思就是講讀取到陣列中的資料拼在fos裡面,那麼fos可以無限往後拼嗎?fos可以放多長進去呢?

這裡我們需要看下原始碼:

    public synchronized void write(byte b[], int off, int len) {
        if ((off < 0) || (off > b.length) || (len < 0) ||
            ((off + len) - b.length > 0)) {
            throw new IndexOutOfBoundsException();
        }
        ensureCapacity(count + len);
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }

這裡有一個ensureCapacity的來做一個累加

關於ensureCapacity我們看下這裡

    private void ensureCapacity(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - buf.length > 0)
            grow(minCapacity);
    }

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = buf.length;
        int newCapacity = oldCapacity << 1;
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        buf = Arrays.copyOf(buf, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

其實有限制MAX_ARRAY_SIZE.

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

那麼Integer.MAX_VALUE是多少呢?

public final class Integer extends Number implements Comparable<Integer> {
    /**
     * A constant holding the minimum value an {@code int} can
     * have, -2<sup>31</sup>.
     */
    public static final int   MIN_VALUE = 0x80000000;

    /**
     * A constant holding the maximum value an {@code int} can
     * have, 2<sup>31</sup>-1.
     */
    public static final int   MAX_VALUE = 0x7fffffff;

這裡我們可以看到是2的31次方-1

為什麼最大值是2的31次方-1呢?

TODO:這裡先空著 

這裡需要思考一個問題:

如果d:/write.txt這個檔案不存在會怎麼樣呢?

如果沒有這個檔案的話是會自動建立的,當然前提是你這個目錄有相關的許可權。

原始碼中是這樣寫的:

/**
 * A file output stream is an output stream for writing data to a
 * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not
 * a file is available or may be created depends upon the underlying
 * platform.  Some platforms, in particular, allow a file to be opened
 * for writing by only one <tt>FileOutputStream</tt> (or other
 * file-writing object) at a time.  In such situations the constructors in
 * this class will fail if the file involved is already open.
 *
 * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes
 * such as image data. For writing streams of characters, consider using
 * <code>FileWriter</code>.
本文為此部落格閱讀後加上自己看的一些東西整理