一、超类:
字节流: InputStream(读入流) OutputStream(写出流)
字符流: Reader(字符 读入流) Writer (字符写出流)
1.文件操作流:
字节流: FileInputStream ,FileOutputStream
字符流: FileReader, FileWriter(用法与字节流基本相同)
2.缓冲流:
字节缓冲流: BufferedInputStream,BufferedOutputStream
字符缓冲流:BufferedReader ,BufferedWriter
缓冲流是对流的操作的功能的加强,提高了数据的读写效率。既然缓冲流是对流的功能和读写效率的加强和提高,所以在创建缓冲流的对象时应该要传入要加强的流对象。
3.对象流:
ObjectInputStream ,ObjectOutputStream
不同于以上两种类型的流这里只能用字节对对象进行操作原因可以看上篇的编码表比照原理
4.转换流:
这类流是用于将字符转换为字节输入输出,用于操作字符文件,属于字符流的子类,所以后缀为reader,writer;前缀inputstream,outputstream;注 :要传入字节流作为参赛
InputStreamReader: 字符转换输出流
OutputStreamWriter:字符转换输入流
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
/*1.读取文件的内容
*
*/
public class Read {
//1.1 使用FileInputStream流来读取有中文的内容时,读出来的是乱码,因为使用InputStream流里面的read()方法读取内容时是一个字节一个字节地读取的,而一个汉字是占用两个字节的;
//使用FileReader流来读取内容时,中英文都可以正确显示,因为Reader流里面的read()方法是一个字符一个字符地读取的,这样每次读取出来的都是一个完整的汉字。
public static void FisOrFr(String readPath){
File file=new File(readPath);
int c=0;
// FileInputStream fis=null;
FileReader fis=null;
try {
// fis=new FileInputStream(file);
fis=new FileReader(file);
while ((c=fis.read())!=-1) { //返回-1表示已经读取到文件的末尾
System.out.print((char)c); //“char(b)”把使用数字表示的汉字和英文字母转换成字符输入(不使用“(char)b”进行转换,直接打印出来的c就是数字,而不是英文和中文)
}
fis.close();
} catch (FileNotFoundException e) {
System.out.println("找不到指定路径!");
System.exit(-1); //系统非正常退出
e.printStackTrace();
} catch (IOException e) {
System.out.println("文件读取错误!");
System.exit(-1);
e.printStackTrace();
}
}
//1.2 可以使用read()方法一次读入一个字节,并以int类型返回,或是使用read()方法时读入至一个byte数组,byte数组的元素有多少个,就读入多少个字节
//在将整个文件读取完成或写入完毕的过程中,这么一个byte数组通常被当作缓冲区,因为这么一个byte数组通常扮演承接数据的中间角色
public static void FisAndByte(String readPath){
FileInputStream fis=null;
int c=-1;
try {
fis=new FileInputStream(readPath);
byte[] bytes=new byte[512];
while ((c=fis.read(bytes, 0, bytes.length))!=-1) { //从输入流中最多读取bytes.length个字节的数据,存放到偏移量为0的bytes数组中。
System.out.println(new String(bytes));
}
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//1.3 读取文件内容+缓冲流
public static void FisIsrBr(String readPath){
//1.获得文件句柄
File file = new File(readPath);
try {
//2.读取文件内容并存入fis对象的内存中
FileInputStream fis = new FileInputStream(file);
//3.对fis内存中数据以gbk方式进行解读
InputStreamReader isr = new InputStreamReader(fis, "gbk");
//4.字节码转成字符码,读取字符码内容并打印到控制台
BufferedReader br = new BufferedReader(isr); //4.1、转换成IO可以识别的数据,就需要调用字节码读取的方法BufferedReader()
String lineTxt =null;
while((lineTxt=br.readLine())!=null){ //4.2、同时使用bufferedReader()的readline()方法读取txt文件中的每一行数据
System.out.println(lineTxt);
}
//5.关闭缓冲流(最好在finally中关闭)
br.close();
} catch (FileNotFoundException e) {
System.out.println("未找到文件!");
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
System.out.println("文件读取错误!");
e.printStackTrace();
}
}
//1.4 读取文档内容(中文乱码、英文不全):
public static void FisBis(String readPath){
FileInputStream fis=null;
BufferedInputStream bis=null;
try {
fis=new FileInputStream(readPath);
bis=new BufferedInputStream(fis); // 在FileInputStream节点流的外面套接一层处理流BufferedInputStream
// System.out.println((char)bis.read());
// bis.mark(100); //在第100个字符处做一个标记
int c=0;
for (int i = 0; i <=100&&(c=bis.read())!=-1; i++) {
System.out.print((char)c);
}
// bis.reset(); // 重新回到原来标记的地方
bis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
/*2.写入到文件
*
*/
public class Write {
//2.1 使用键盘输入一段文章,将文章保存在文件write.txt中(中文乱码)
public static void FosAndByte(String writePath){
System.out.println("请输入:");
FileOutputStream fos=null;
byte[] bytes=new byte[512]; //或者 byte byres[] = new byte[512];
int count=512;
try {
count=System.in.read(bytes);
fos=new FileOutputStream(writePath);
fos.write(bytes, 0, bytes.length); //将参数bytes的从偏移量0开始的bytes.lenth个字节写到输出流。
fos.close();
System.out.println("save ");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//2.2 键盘输入流读到内存
public static void IsrBrAndFwBw(String writePath){
BufferedReader br=null;
BufferedWriter bw=null;
try {
System.out.println("请输入内容:");
InputStreamReader isr=new InputStreamReader(System.in);
br=new BufferedReader(isr);
FileWriter fw=new FileWriter(writePath);
bw=new BufferedWriter(fw);
// OutputStreamWriter osw=new OutputStreamWriter(null, "C:\\bea\\copy.txt"); //null ??
// bw=new BufferedWriter(osw);
String s=null;
while ((s=br.readLine()).length()>0) { //从键盘读入字符,并写入到文件中BufferedReader类的方法:String readLine(),作用:读一行字符串,以回车符为结束
bw.write(s, 0, s.length()); //从缓冲区将字符串s从0开始,s.lenth()长度的字符串写到某处
bw.flush(); //关键的一行代码;如果没有加这行代码,数据只是保存在缓冲区中,而没有写进文件,加了这行才能将数据写入目的地
}
} catch (IOException e) {
System.out.println("读写异常!");
e.printStackTrace();
}finally{
try {
br.close();
bw.close();
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
//2.3 转换流--向文件中写入数据并在后面添加数据
public static void FosOsw(String writePath){
FileOutputStream fos=null;
OutputStreamWriter osw=null;
try {
fos=new FileOutputStream(writePath);
osw=new OutputStreamWriter(fos);
osw.write("yagnxu123456");
System.out.println(osw.getEncoding()); //使用getEncoding()方法取得当前系统的默认字符编码
osw.close();
// 如果在调用FileOutputStream的构造方法时没有加入true,那么新加入的字符串就会替换掉原来写入的字符串,在调用构造方法时指定了字符的编码
fos=new FileOutputStream(writePath, true);
osw=new OutputStreamWriter(fos, "ISO8859_1");
osw.write("xuyang"); // 再次向指定的文件写入字符串,新写入的字符串加入到原来字符串的后面
System.out.println(osw.getEncoding());
osw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
/*3.读取内容后写入到文件
*
*/
public class ReadAndWrite {
//3.1 将yx.txt中内容复制到指定txt中(含中文)
public static void FisFos(String readPath,String writePath){
File file=new File(readPath);
File fileCopy=new File(writePath);
FileInputStream fis=null;
FileOutputStream fos=null;
int c=0;
try {
fis=new FileInputStream(file);
fos=new FileOutputStream(fileCopy);
while ((c=fis.read()) != -1) {
fos.write(c);
}
fis.close();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
System.err.println("FileStreamsTest: " + e);
// e.printStackTrace();
}
System.out.println("操作完成!");
}
//3.2 向指定文件中写入数据并读取显示到控制台(写入有些问题!)
public static void FrFw(String readPath,String writePath){
FileReader fr=null;
FileWriter fw=null;
try {
fr=new FileReader(readPath);
fw=new FileWriter(writePath);
//for循环执行的过程中应该使用了“(char)c”进行强制转换,即把整数转换成字符来显示,因为打开写入数据的文件,里面显示的数据并不是0~60000内的整数,而是不同国家的文字的表示方式
for (int i = 0; i <=60000; i++) { //用for循环把0~60000里面的所有整数都输出;相当于是把全世界各个国家的文字都0~60000内的整数的形式来表示
fw.write(i);
}
int c=0;
while ((c=fr.read())!=-1) {
System.out.print((char)c); //控制台输出yx.txt内容
}
fr.close();
fw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("操作完成!");
}
//3.3 控制台连续输入文件内容以end结束 ,ConsoleToFileEnd 控制台到文件end结束
public static void ConsoleToFileEnd(String readPath,String writePath)throws IOException {
InputStreamReader isr=new InputStreamReader(System.in);//1.键盘输入内容--将控制台内容输入到isr流中 ~~InputStreamReader:处理字符流的抽象类(将字节流转为字符流)
BufferedReader br=new BufferedReader(isr); //2.缓存输入流,把控制台的内容尽可能将缓存流塞满 ~~缓冲方式读取文本
File datafile=new File("C:/Users/Administrator/Desktop/YX"); //3.路径下txt文件
datafile.mkdirs(); //创建文件夹
File datafile1=new File(datafile.getAbsolutePath(),"yangxu.txt");
datafile1.createNewFile(); //若该文件不存在,则创建该文件
//4.判断文件datefile1是否 代码的未初始化???
if(datafile1==null){
System.out.println("创建数据文件,程序退出!");
return;
}
//5.输出流PrintWriter~~该类可用来创建一个文件并向文本文件写入数据
PrintWriter pw=null;
try{
pw=new PrintWriter(datafile1); //生成a.txt文件的一个输出流
}catch(FileNotFoundException e1){
e1.printStackTrace();
return;
}
String content=null;
String endMark="end";
try{
System.out.println("请输入要写入文件的内容,以end结束!");
while((content=br.readLine())!=null){
if(content.equalsIgnoreCase(endMark)){ //判断是否为end
break;
}
pw.write(content+"\b"); //往pw流中输入内容并回车 \r\n换行 \t\n Tab键? \t 相当于tab,缩进 \b 换成 一个黑点
} //\n 回车换行?? \r 换行--回车到当前行行首??
pw.close();
br.close();
}catch(IOException e){
e.printStackTrace();
}
}
//3.4 复制文件内容
public static void FrFwAndChar(String readPath,String writePath){
FileReader fr=null;
FileWriter fw=null;
int c=-1;
try {
fr=new FileReader(readPath);
fw=new FileWriter(writePath);
char[] chars=new char[1024];
while ((c=fr.read(chars, 0, chars.length))!=-1) {
fw.write(chars, 0, c);
}
fw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("操作完成!");
}
//3.5 拷贝音乐文件
public static void FisFosAndByte(String readPath,String writePath){
File file=new File(writePath);
if (!file.exists()) { //判断也可以注释掉,因为如果写入文件不存在,系统会自动创建一个文件,而不会报错。
file.mkdir();
// file.createNewFile(); //需要throws IOException
}
FileInputStream fis=null;
FileOutputStream fos=null;
int c=-1;
try {
fis=new FileInputStream(readPath);
// fos=new FileOutputStream("C:\\bea\\121.mp3");
fos=new FileOutputStream(file.getAbsolutePath()+File.separator+"121.mp3"); //file.getAbsolutePath()返回抽象路径名的绝对路径名字符串;File.separator 与系统有关的默认名称分隔符
byte[] bytes=new byte[100]; //循环通过输入流,读取数据,边读边写
while ((c=fis.read(bytes, 0, bytes.length))!=-1) { // 从输入流中最多读取bytes.length个字节的数据,存放到偏移量为0的bytes数组中
fos.write(bytes, 0, c); //返回值:是真实读取到的字节数,如果到了流的末尾,返回-1(推荐使用这个方法,读到多少字节就写入多少字节)
}
fis.close();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//3.6 FileReader读取文件内容+FileWriter写入随机数
public static void FrBrAndFwBw(String readPath,String writePath){
FileReader fr=null;
FileWriter fw=null;
BufferedReader br=null;
BufferedWriter bw=null;
String s=null;
try {
fr=new FileReader(readPath);
br=new BufferedReader(fr); //在节点流FileReader的外面再套一层处理流BufferedReader
while ((s=br.readLine())!=null) { //BufferedReader处理流提供的readLine()方法读取文件中的数据时是一行一行读取的;
System.out.println(s); //--循环结束的条件是使用readLine()方法读取数据返回的字符串为空值后,表示已经读取到文件的末尾了
}
fw=new FileWriter(writePath);
bw=new BufferedWriter(fw); //在节点流FileWriter的外面再套一层处理流BufferedWriter
for (int i = 0; i <100; i++) { //valueOf把一个double类型的数转换成字符串(valueOf()是一个静态方法,所以可以使用“类型.静态方法名”的形式来调用 );
s=String.valueOf(Math.random()); //--Math.random() 会生成一系列介于0~1之间的随机数;
bw.write(s);
bw.newLine(); //调用newLine()方法使得每写入一个随机数就换行显示
}
bw.flush(); //调用flush()方法清空缓冲区
bw.close();
br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//3.7 打印流PrintStream---这个小程序是重新设置打印输出的窗口(把默认在命令行窗口输出打印内容设置成其他指定的打印显示窗口)
public static void FosPs(String writePath){
FileOutputStream fos=null;
PrintStream ps = null;
try{
fos = new FileOutputStream(writePath);
ps = new PrintStream(fos); //在输出流的外面套接一层打印流,用来控制打印输出
if(ps != null){
System.setOut(ps); //这里调用setOut()方法改变了输出窗口,以前写System.out.print()默认的输出窗口就是命令行窗口.
//但现在使用System.setOut(ps)将打印输出窗口改成了由ps指定的文件里面,通过这样设置以后,打印输出时都会在指定的文件内打印输出
//在这里将打印输出窗口设置到了log.txt这个文件里面,所以打印出来的内容会在log.txt这个文件里面看到
}
for(char c=0;c<=60000;c++){
System.out.print(c+"\t"); //把世界各国的文字打印到log.txt这个文件中去
}
}catch(Exception e){
e.printStackTrace();
}
}
//3.8 对象流序列化和反序列化:
//直接实现Serializable接口的类是JDK自动把这个类的对象序列化,而如果实现public interface Externalizable extends Serializable的类则可以自己控制对象的序列化,
//建议能让JDK自己控制序列化的就不要让自己去控制。
//凡是要将一个类的对象序列化成一个字节流就必须实现Serializable接口
//Serializable接口中没有定义方法,Serializable接口是一个标记性接口,用来给类作标记,只是起到一个标记作用。
//这个标记是给编译器看的,编译器看到这个标记之后就可以知道这个类可以被序列化 如果想把某个类的对象序列化,就必须得实现Serializable接口
public static void FisOis(String readPath,String writePath) {
try {
FileOutputStream fos = new FileOutputStream(writePath);
ObjectOutputStream oos = new ObjectOutputStream(fos); // ObjectOutputStream流专门用来处理Object的,在fos流的外面套接该流就可以直接把一个Object写进去
oos.writeObject("123456"); // 直接把一个t对象写入到指定的文件里面
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream(readPath);
ObjectInputStream ois = new ObjectInputStream(fis); // ObjectInputStream专门用来读一个Object的
Object o=ois.readObject(); // 直接把文件里面的内容全部读取出来然后分解成一个Object对象
System.out.println(0);
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
/*4.其它
*
*/
public class Test {
//4.1 随机数的输出!
//数据流:通过bais这个流往外读取数据的时候,是一个字节一个字节地往外读取的,因此读出来的数据无法判断是字符串还是bool类型的值,因此要在它的外面再套一个流,
//通过dataInputStream把读出来的数据转换就可以判断了。
public static void BaosDos(){
ByteArrayOutputStream baos = new ByteArrayOutputStream(); //在调用构造方法时,首先会在内存里面创建一个ByteArray字节数组
DataOutputStream dos = new DataOutputStream(baos); //在输出流的外面套上一层数据流,用来处理int,double类型的数
try{
dos.writeDouble(Math.random()); //把产生的随机数直接写入到字节数组ByteArray中
dos.writeBoolean(true); //布尔类型的数据在内存中就只占一个字节
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
System.out.println(bais.available());
DataInputStream dis = new DataInputStream(bais);
System.out.println(dis.readDouble()); //先写进去的就先读出来,调用readDouble()方法读取出写入的随机数
System.out.println(dis.readBoolean()); //后写进去的就后读出来,这里面的读取顺序不能更改位置,否则会打印出不正确的结果
dos.close();
bais.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
二、缓冲输入输出流(BufferedInputStream/BufferedOutputStream)详解:
1.缓冲流就是每一个数据流分配一个缓冲区,一个缓冲区就是一个临时存储数据的内存。这样可以减少访问硬盘的次数,提高传输效率。
BufferedInputStream:当向缓冲流写入数据时候,数据先写到缓冲区,待缓冲区写满后,系统一次性将数据发送给输出设备。
BufferedOutputStream :当从向缓冲流读取数据时候,系统先从缓冲区读出数据,待缓冲区为空时,系统再从输入设备读取数据到缓冲区。
2.文件与内存间转换:
① 将文件读入内存:将BufferedInputStream与FileInputStream相接
② 将内存写入文件:将BufferedOutputStream与 FileOutputStream相接
③ 键盘输入流读到内存:将BufferedReader与标准的数据流相接
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader bin=new BufferedReader(isr);
三、其他介绍:
1.在电脑上的数据有三种存储方式:外存、内存、缓存(如电脑上的硬盘,磁盘,U盘等都是外存,在电脑上有内存条,缓存是在CPU里面的)
2.Java中字符是采用Unicode标准,一个字符是16位,即一个字符使用两个字节来表示,为此JAVA中引入了处理字符的流
流序列中的数据既可以是未经加工的原始二进制数据,也可以是经一定编码处理后符合某种格式规定的特定数据
因此Java中的流分为两种:
1) 字节流:数据流中最小的数据单元是字节(用来存储数据的最小单位是字节 byte,用来表示信息的最小单位是位 bit,一个字节是8位即1KB=1024B=1024*8b )
字符流:Java中的字符是Unicode编码,一个字符是16位即占用两个字节(在处理字符流时涉及了字符编码的转换问题)。
2)Reader类能够将输入流中采用其他编码类型的字符转换为Unicode字符,然后在内存中为其分配内存
Writer类能够将内存中的Unicode字符转换为其他编码类型的字符,再写到输出流中。
3)在字节流转化为字符流时,实际上就是byte[]转化为String
在字符流转化为字节流时,实际上是String转化为byte[]
3.整个Java.io包中最重要的就是5个类和一个接口:
5个类指的是OutputStream、InputStream、Writer、Reader、File(File类是IO包中唯一代表磁盘文件本身的对象。通过File来创建,删除,重命名文件);
一个接口指的是Serializable.
4.IOException异常类的子类:
public class EOFException :非正常到达文件尾或输入流尾时,抛出这种类型的异常。
public class FileNotFoundException:当文件找不到时,抛出的异常。
public class InterruptedIOException:当I/O操作被中断时,抛出这种类型的异常。
5.java系统自带的标准数据流:java.lang.System:
java.lang.System
public final class System extends Object{
static PrintStream err;//标准错误流(输出)
static InputStream in;//标准输入(键盘输入流)
static PrintStream out;//标准输出流(显示器输出流)
}