笔记
以数据流的数据单元划分可分为字节流,既最小的数据单元的是字节,在Java中用
InputStream
和OutputStream
来抽象和描述,字符流,既最小的数据单元是字符,用Reader
和Writer
来描述.InputStream
和OutputStream
都是抽象类,他们的子类实现了各种文件的读写输入流代表从其他介质输入的内存的流,输出流代表从内存输出到其他磁盘或其他介质.
输入流最重要的方法是
read()
方法,它返回一个整数,一个整数有4个字节,所以实际上返回的值为0-255
如果返回-1
代表数据流结束,对于二进制数的话,就是顺序读取8个位,一个字节字节到整型的转换
字节在计算机是以补码的形式存在,如
-9
用补码表示是11110111
,转化为整型是整型的低八位,即00000000 00000000 00000000 11110111
所以转化为整型是247.输入流的重要方法有
int read()
:读取一个字节int read(byte[] b)
从输入流读取若干个字节保存在b参数指定的字节数组中,这时返回的整数表示读取的字节数,如果遇到输入流的结尾表示,则返回-1int read(byte[] b,int off,int len)
从输入流中读取len个字节保存到b指定的字节数组中,off参数表示的是字节数组中开始保存数据的起始下标,这时返回的整数表示读取的字节数,如果遇到输入流的结尾表示,则返回-1read()
方法的几个重载void close()
释放流和有关的系统资源int available()
返回可以从输入流读取的字节数目skip(long n)
跳过指定的字节数输出流的重要方法有
write(int b)
向输出流写出一个字节write(byte[] b)
将指定的字节数组中的全都字节写入到输出流中write(byte[] b,int off,int len)
将指定的字节数组的若干字节输出到输出流,off表示指定字节数组开始输出的下标,len表示输出的字节数.write()
的几个重载close()
关闭输出流释放有关的资源
void flush()
带有缓冲区的子类覆盖了此方法,如
BufferedOutputStream
,带有缓冲区的子类并不会马上将数据写入到输出流中而是等到缓冲区积累了一定的数据才会写入到输出流,通过这个方法可以强制将在缓冲区的数据写入到输出流.输入流的子类
ByteArrayInputStream
将字节数组转化为输入流
FileInputStream
文件输入流,数据源是文件,以字节为基本单位,要注意,从输入流中读取数据的时候不能这样读
while (fileInputStream.read()!=-1){ }
因为输入流每调用read一次,指针将会后移一次,导致读取的数据不完整,应该使用如下方式
FileInputStream fileInputStream = new FileInputStream("testfile");int data;while ((data = fileInputStream.read())!=-1){ System.out.print(data+" ");}
将读取一次的数据存于一个变量之中
也可将输入流读入到一个字节数组中
FileInputStream fileInputStream = new FileInputStream("testfile"); byte[] b = new byte[fileInputStream.available()]; fileInputStream.read(b); for (byte b1:b){ System.out.print(b1+" "); }
管道输入流
管道输入流从一个管道输出流中读取数据,可用于线程之间通信,通常由一个线程向管道输出流写数据,另一个线程从管道输入流中读取数据,当线程执行管道输入流的read()方法时,如果暂时还没有数据,那么这个线程会阻塞,只有另一个线程向管道输出流写入了数据时,阻塞的线程才会恢复运行.
package javaiodemo; import java.io.*;import java.nio.file.FileSystem; import java.nio.file.FileSystems;import java.nio.file.Path; public class Main { public static void main(String[] args) { Sender sender = new Sender(); Receiver receiver = new Receiver(sender); sender.start(); receiver.start(); } } class Sender extends Thread { PipedOutputStream out = new PipedOutputStream(); public PipedOutputStream getOut() { return out; } @Override public void run() { for (int i = 0; i < 100; i++) { try { out.write(i); sleep(100); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } try { out.close(); } catch (IOException e) { e.printStackTrace(); } }} class Receiver extends Thread { PipedInputStream pipedInputStream; public Receiver(Sender sender) { try { pipedInputStream = new PipedInputStream(sender.getOut()); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { try { int data; while ((data = pipedInputStream.read()) != -1) { System.out.print(data + " "); } } catch (IOException e) { e.printStackTrace(); } }}
可以通过sleep来观察接受者线程的阻塞.
输出流
FileOutputStream(File file)
FileOutputStream(String name)
FileOutputStream(String name,boolean append)
ByteArrayOutputStream
将数据写入到字节数组,可以通过
toByteArray()
方法得到写入的字节数组public class Main { public static void main(String[] args) { try { ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write("test".getBytes("UTF-8")); byte[] bytes = out.toByteArray(); for (byte b : bytes) { System.out.print(b+" "); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }}
FileOutputStream
向文件中写入数据,他有三个构造方法
第三个构造函数的第二个参数是是否以追加的方式写入数据
public class Main { public static void main(String[] args) { try { FileOutputStream fileOutputStream = new FileOutputStream("testfile",true); fileOutputStream.write("Tinuv你好".getBytes("UTF-8")); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }}