IO:
- 可以让我们用标准的读写操作来完成对不同设备的读写数据工作。java将IO按照方向划分为输入与输出,参照点是我们写的程序
- 输入:用来读取数据的,是从外界到程序的方向,用于获取数据。
- 输出:用来写出数据的,是从程序到外界的方向,用于发送数据。
- java将IO比喻为"流",即:stream。 就像生活中的"电流"、"水流"一样,它是以同一个方向顺序移动的过程.只不过这里流动的是字节(2进制数据)。所以在IO中有输入流和输出流之分,我们理解他们是连接程序与另一端的"管道"。用于获取或发送数据到另一端。
-
Java定义了两个超类(抽象类):
-
java.io.InputStream:所有字节输入流的超类,其中定义了读取数据的方法,因此将来不管读取的是什么设备(连接该设备的流)都有这些读取的方法,因此我们可以用相同的方法读取不同设备中的数据
-
java.io.OutputStream:所有字节输出流的超类,其中定义了写出数据的方法.
-
文件流:用于读写文件数据的流,用于连接程序与文件(硬盘)的"管道",负责读写文件数据.
-
文件输出流java.io.FileOutputStream:
-
文件输入流java.io.FileInputStream:
单字节写:
package io;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;/*** IO: Input和Output,即:输入与输出** Java将输入和输出用"流Stream"表达,分为输入流和输出流,* 我们可以将它们想象为连接我们的程序和另一个设备之间的"管道",通过它们可以读写设备* Java将输入流和输出流定义了两个对应的超类InputStream和OutputStream:* 1)InputStream:* 输入流,方向是从外界到程序的方向,用于读取数据的流,是一个抽象类,定义了读取字节的相关方法* 2)OutputStream:* 输出流,方向是从程序到外界的方向,用于写出数据的流,是一个抽象类,定义了写出字节的相关方法** 文件流: FileInputStream和FileOutputStream* 文件流继承自InputStream和OutputStream,用于对文件进行读写操作*/
public class FOSDemo {public static void main(String[] args) throws IOException {/*文件输出流两个常用的构造器:1)FileOutputStream(String fileName)2)FileOutputStream(File file)文件流创建时如果指定的文件不存在则会自动创建,前提是该文件所在的目录必须存在,若不存在则发生异常*/File file = new File("fos.dat");FileOutputStream fos = new FileOutputStream(file,true); //根据File实例定义文件输出流//FileOutputStream fos = new FileOutputStream("fos.dat"); //定义文件输出流/*OutputStream(所有字节输出流的超类)上定义了写出字节的相关方法:write()void write(int d):通过该输出流向目标位置写出1个字节,写出的是给定的int值对应的2进制的"低八位"当fos.write(1)时,向fos.dat中写入了1个字节int值1的2进制样子: 00000000 00000000 00000000 00000001^^^^^^^^写入该字节write()后,fos.dat文件内容(长度为1字节):00000001当fos.write(2)时,又向fos.dat中写入了1个字节int值2的2进制样子: 00000000 00000000 00000000 00000010^^^^^^^^写入该字节write()后,fos.dat文件内容(长度为2字节):00000001 00000010*//*当fos.write(-1)时,向fos中写入了1个字节int值-1的2进制样子:11111111 11111111 11111111 11111111^^^^^^^^写入该字节write()后,fos.dat文件内容11111111*/fos.write(1); //向fos.dat中写入了1个字节fos.write(2); //向fos.dat中又写入了1个字节//fos.write(-1);//认为读出256的发花 认为读出255的发火箭 认为读出0的发666 认为读出1的发小汽车System.out.println("写出完毕!");fos.close(); //关闭流}
}
单字节读:
package io;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;/*** 文件输入流,读取文件数据*/
public class FISDemo {public static void main(String[] args) throws IOException {/*FileInputStream(String filename)FileInputStream(File file)上述两种构造器创建文件输入流时,如果参数表达的是一个文件则可以正常实例化若表达的文件不存在或表达的是一个目录则会抛出异常*/FileInputStream fis = new FileInputStream("fos.dat"); //定义文件输入流/*InputStream超类上定义了读取一个字节的方法:(所有的字节输入流都具有该方法)int read():读取1个字节,并以int形式返回1)返回的int值对应的2进制中只有"低八位"是有效的,高24位全部补02)如果该方法返回的int值为-1(32个1)时,则表示流读取了末尾第1次调用: int d = fis.read(); //读取第1个字节fos.dat的数据:00000001 00000010 文件末尾^^^^^^^^读取的字节此时变量d对应的2进制样子: 00000000 00000000 00000000 00000001|------补充24个0-----------| 读取的字节----十进制的1第2次调用: d = fis.read(); //读取了第2个字节fos.dat的数据:00000001 00000010 文件末尾^^^^^^^^读取的字节此时变量d对应的2进制样子: 00000000 00000000 00000000 00000010|------补充24个0-----------| 读取的字节----十进制的2第3次调用: d = fis.read(); //读取了文件末尾fos.dat的数据:00000001 00000010 文件末尾^^^^^^^没有字节了此时变量d对应的2进制样子: 11111111 11111111 11111111 11111111|-------------32个二进制的1----------|----十进制的-1*//*调用: int d = fis.read();fos.dat的数据:11111111 文件末尾^^^^^^^^此时变量对应的2进制样子: 00000000 00000000 00000000 11111111|------补充24个0-----------| 读取的字节----十进制的255*/int d = fis.read(); //读取第1个字节System.out.println(d); //输出10进制数据:1//d = fis.read(); //读取了第2个字节//System.out.println(d); //输出10进制数据:2//d = fis.read(); //读取文件末尾了//System.out.println(d); //输出10进制数据:-1,表示到文件末尾了fis.close(); //关闭流}
}
单字节文件复制:慢
package io;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;/*** 文件复制:将一个文件中的数据读出来,然后写入到另一个文件中*/
public class CopyDemo {public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("zsw.jpg");FileOutputStream fos = new FileOutputStream("zsw_cp.jpg");/*zsw.jpg图片数据:11101011 10011010 01101101 11101111 10011001 00111010 01101110...第1次调用: d=fis.read();11101011 10011010 01101101 11101111 10011001 00111010 01101110...^^^^^^^^读取的字节fos.write(d); //将d对应的2进制的"低八位"写入到文件zsw_cp.jpgd: 00000000 00000000 00000000 11101011^^^^^^^^写入的字节zsw_cp.jpg的内容:11101011......*/long start = System.currentTimeMillis(); //自1970年1月1日0时到此时此刻的毫秒数int d; //记录每次读取到的字节while((d=fis.read())!=-1){ //每次循环读取1个字节到d中,判断若不是-1,表示没有读取末尾fos.write(d); //将读出来的字节写入到要复制的文件中}long end = System.currentTimeMillis();System.out.println("复制完毕!耗时:"+(end-start)+"ms");fis.close();fos.close();}
}
块读写的文件复制操作:快
package io;import jdk.management.resource.internal.inst.SimpleAsynchronousFileChannelImplRMHooks;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;/*通过提高每次读写的数据量减少实际读写的次数,可以提供读写的效率一组字节的读写:块读写*/
public class CopyDemo2 {public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("zsw.jpg");FileOutputStream fos = new FileOutputStream("zsw_cp2.jpg");/*InputStream超类中定义了块读取数据的方法:int read(byte[] data)一次性读取给定的字节数组data总长度的字节量,并存入到字节数组中,返回值表示实际读取到了多少个字节,若返回-1表示读到了末尾OutputStream超类上也定义了块写字节的方法:void write(byte[] data)一次性将给定的字节数组data中的所有字节写出void write(byte[] data,int offset,int len)一次性将给定的字节数组data从下标offset处开始的连续len个字节写出*//*zsw.jpg图片数据:11101011 10011010 01101101 11101111 10011001 00111010 01101110 文件末尾byte[] data = new byte[3]; //3个字节第1次调用fis.read(data)时:----一次性读取3个字节11101011 10011010 01101101 11101111 10011001 00111010 01101110 文件末尾^^^^^^^^ ^^^^^^^^ ^^^^^^^^|-----本次读到的3个字节-----|data: {11101011 10011010 01101101}第1次调用fos.write(data)时:----一次性写入3个字节zsw_cp2.jpg图片数据:11101011 10011010 01101101第2次调用fis.read(data)时:----一次性读取3个字节11101011 10011010 01101101 11101111 10011001 00111010 01101110 文件末尾^^^^^^^^ ^^^^^^^^ ^^^^^^^^|-----本次读到的3个字节-----|data:{11101111 10011001 00111010} //将第1次读的3个字节完整替换第2次调用fos.write(data)时:----一次性写入3个字节zsw_cp2.jpg图片数据:11101011 10011010 01101101 11101111 10011001 00111010第3次调用fis.read(data)时:----一次性读取3个字节11101011 10011010 01101101 11101111 10011001 00111010 01101110 文件末尾^^^^^^^^ ^^^^^^^^ ^^^^^^^^仅读取到1个字节data:{01101110 10011001 00111010} //将第2次读取的第1个字节替换了,后两个还是上次的数据|-读取的-| |-----旧数据------|实际只读取了1个字节,所以也只写入1个字节zsw_cp2.jpg图片数据:11101011 10011010 01101101 11101111 10011001 00111010 01101110*/long start = System.currentTimeMillis();byte[] data = new byte[1024*10]; //10kbint len; //记录每次实际读取的字节数while((len=fis.read(data))!=-1){ //每次读取10kb并判断是否读取到了末尾//将字节数组byte从下标0开始连续len个字节写出(做到读多少就写多少)fos.write(data,0,len);}long end = System.currentTimeMillis();System.out.println("复制完毕!耗时:"+(end-start)+"ms");fis.close();fos.close();/*zsw.jpg图片数据:11101011 10011010 01101101 11101111 10011001 00111010 01101110 文件末尾byte[] data = new byte[3]; //3个字节第1次调用fis.read(data)时:----一次性读取3个字节11101011 10011010 01101101 11101111 10011001 00111010 01101110 文件末尾^^^^^^^^ ^^^^^^^^ ^^^^^^^^|-----本次读到的3个字节-----|data: {11101011 10011010 01101101}第1次调用fos.write(data)时:----一次性写入3个字节zsw_cp2.jpg图片数据:11101011 10011010 01101101第2次调用fis.read(data)时:----一次性读取3个字节11101011 10011010 01101101 11101111 10011001 00111010 01101110 文件末尾^^^^^^^^ ^^^^^^^^ ^^^^^^^^|-----本次读到的3个字节-----|data:{11101111 10011001 00111010} //将第1次读的3个字节完整替换第2次调用fos.write(data)时:----一次性写入3个字节zsw_cp2.jpg图片数据:11101011 10011010 01101101 11101111 10011001 00111010第3次调用fis.read(data)时:----一次性读取3个字节11101011 10011010 01101101 11101111 10011001 00111010 01101110 文件末尾^^^^^^^^ ^^^^^^^^ ^^^^^^^^仅读取到1个字节data:{01101110 10011001 00111010} //将第2次读取的第1个字节替换了,后两个还是上次的数据|-读取的-| |-----旧数据------|zsw_cp2.jpg图片数据:11101011 10011010 01101101 11101111 10011001 00111010 01101110 10011001 00111010*//*long start = System.currentTimeMillis();byte[] data = new byte[1024*10]; //10kbwhile(fis.read(data)!=-1){ //每次读取10kb并判断是否读取到了末尾fos.write(data); //一次写入10kb数据}long end = System.currentTimeMillis();System.out.println("复制完毕!耗时:"+(end-start)+"ms");fis.close();fos.close();*/}
}
写文本数据:
package io;import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;/*** 向文件中写入文本数据*/
public class WriteStringDemo {public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("fos.txt",true);/*文字与2进制的对应关系有各种标准:字符集------了解支持中文的字符集常见的有:1)UTF-8:unicode的转换编码1.1)英文、符号、数字各占1个字节,但中文占3个字节2)GBK:国标编码2.1)英文、符号、数字各占1个字节,但中文占2个字节*/String line = "心在跳是爱情如烈火,你在笑疯狂的人是我";byte[] data = line.getBytes(StandardCharsets.UTF_8); //将line的内容按照utf-8编码转换为字节数组fos.write(data);fos.write(",爱如火会温暖了心窝".getBytes(StandardCharsets.UTF_8));System.out.println("写出完毕!");fos.close();}
}
读取文本数据:
package io;import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;/*** 读取文本数据*/
public class ReadStringDemo {public static void main(String[] args) throws IOException {File file = new File("fos.txt");FileInputStream fis = new FileInputStream(file);byte[] data = new byte[(int)file.length()]; //创建与文件等长的字节数组fis.read(data); //一次性读取数据到data中String line = new String(data, StandardCharsets.UTF_8); //将data中的字节还原为字符串System.out.println(line);fis.close();}
}