> 文章列表 > IO流基础

IO流基础

IO流基础

IO流

IO就是Input和Output的简写头字母,也就是输入和输出的意思

就是读写数据时像流水一样从一端流到另外一端,因此得名为"流"
也可以理解为数据从硬盘与程序之间交互的这个过程

文件

文件我们都不陌生,在日常生活中使用的word文件,excel文件,pdf文件等等…都是文件
简单的说 “文件”就是保存数据的地方。

输出流和输入流

文件在程序中是以流的形式来操作的
流:数据在数据源(文件)和程序(内存)之间经历的途径

输入流:数据从数据源(文件)到程序(内存)的路径
输出流:数据从程序(内存)到数据源(文件)的路径
抽象点形式就是,例如,一个java程序要从C盘的某个文件夹中读取某个文件的数据。这个就是输入流
如果是一个java程序要创建一个文件,且在这个文件中写数据。然后将这个文件保存在C盘中,这个就是输出流

IO流基础

创建文件

IO流基础

在java中可以使用一个类来在硬盘中创建文件,也就是输出流。
下面用File类来创建一个文件。

File类有三种构造器来创建文件的方法

第一种:
new File(String pathname)//根据路劲构建一个File对象
第二种:
new File(File parent,String child)//根据父目录文件+子路径构建
第三种
new File(String parent,String child)//根据父目录+子路径构建

public class test1 {public static void main(String[] args) {//第一种  new File(String pathname)//根据路劲构建一个File对象String filePath = "D:\\\\test/news1.txt";//路劲和文件名以文件后缀File file = new File(filePath);//在程序内存中创建一个file对象try {file.createNewFile();//将文件写入硬盘中System.out.println("创建成功");} catch (IOException e) {e.printStackTrace();}//第二种  new File(File parent,String child)//根据父目录文件+子路径构建File parentFile = new File("D:\\\\");//定义父类目录文件String fileName = "test/news2.txt";//定义子路劲,以及创建的文件名和后缀File file2 = new File(parentFile, fileName);//在内存中创建file对象try {file2.createNewFile();//将文件写入硬盘中System.out.println("创建成功");} catch (IOException e) {e.printStackTrace();}//第三种  new File(String parent,String child)//根据父目录+子路径构建String parentFile1 = "D:\\\\";//定义父类目录文件String childFile = "test/news3.txt";//定义子路劲,以及创建的文件名和后缀File file3 = new File(parentFile1, childFile);//在内存中创建file对象try {file3.createNewFile();//将文件写入硬盘中System.out.println("创建成功");} catch (IOException e) {e.printStackTrace();}}
}

File类的常用方法

File有很多方法,包括对文件的操作,信息读取等等…

获取文件的名字:getName()
获取文件的绝对路径:getAbsolutePath()
获取文件的父类目录:getParent()
返回文件的大小(字节:file.length()
文件是否存在:exists()
是不是一个文件:isFile()
是不是一个目录:isDirectory()

public class test2 {public static void main(String[] args) {File file = new File("D:\\\\test/news1.txt");System.out.println("获取文件的名字"+file.getName());System.out.println("获取文件的绝对路劲"+file.getAbsolutePath());System.out.println("获取文件的父类目录"+file.getParent());System.out.println("返回文件的大小(字节)"+file.length());System.out.println("文件是否存在"+file.exists());System.out.println("是不是一个文件"+file.isFile());System.out.println("是不是一个目录"+file.isDirectory());}
}

运行结果:
获取文件的名字news1.txt
获取文件的绝对路径D:\\test\\news1.txt
获取文件的父类目录D:\\test
返回文件的大小(字节)5
文件是否存在true
是不是一个文件true
是不是一个目录false

File类对目录的创建和删除

目录也就是文件夹,在编程中其实目录也可以看做是一个文件。下面有几种方法可以对目录进行创建和删除

mkdir:创建一级目录
mkdirs:创建多级目录
delete:删除空目录或文件

小练习

  1. 判断D盘中的news1.txt是否存在,如果存在就删除
public static void main(String[] args) {File file = new File("D:\\\\test/news1.txt");if (file.exists()){file.delete();}else{System.out.println("文件不存在");}}
  1. 判断D盘中的demo2目录是否存在,如果存在就删除,否则提示不不存在
public static void main(String[] args) {File file = new File("D:\\\\demo2");if (file.exists()){file.delete();}else{System.out.println("文件不存在");}}
  1. 判断D盘中的demo2目录是否存在,如果存在就提示存在,否则就创建,且在demo2中创建目录a,a中创建b目录
public static void main(String[] args) {File file = new File("D:\\\\demo2\\\\a\\\\b");if (file.exists()){System.out.println("存在");}else{System.out.println("不存在,正在创建");file.mkdirs();}}

IO流原理和流的分类

IO流的原理

IO就是Input和Output的缩写
IO技术是非常实用的技术,用于处理数据间的传输,如读/写,网络通讯等等

java程序中对于数据的输入和输出操作是以“流(stream)”的方式进行的
java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过方法输入或输出

input输入:读取外部数据(磁盘,光盘等存储设备的数据)到程序中
output:将程序的数据输出到磁盘光盘这些设备中

流的分类

:程序使用相同的方式来访问不同的输入/输出源。stream(流)是从起源(source)到接收的(sink)的有序数据
通俗的说:例如 一个人在家网购,商品从商家 到 网购人的手中,这个过程有物流公司来实现。那么这个物流公司就可以看做是一个流,快递小哥也可以看做是流。

  • 按操作数据单位,流可以分为:字节流,字符流
  • 按数据流的流向不同可以分为:输出流,输入流
  • 按流的角色可以分为:节点流,处理流/包装流

字节流可以处理一切,字符流只能处理纯文本。
java中提供了很多流的类用于操作不同类似的文件

抽象基类 字节流 字符流
输入流 inputStream Reader
输出流 outputStream Writer
java的IO流共涉及40多个类,但是其实都是从4个抽象基类派生的
由上面4个抽象类派生的子类名称都是以其父类名作为子类名后缀的

IO流基础

inputStream抽象类

inputStream抽象类是字节输入流基类,用于从外部读取文件,并对文件进行操作

FileInputStream类

FileInputStream是inputStream的子类,是一个文件输入流。
可以理解为,物流公司的快递小哥,负责拿到你的包裹为你处理派送等任务。
类图
IO流基础
构造方法

  1. FileInputStream(File file),打开一个到实际文件的连接来创建一个FileInputStream对象,该文件通过File对象指定
  2. FileInputStream(FileDescriptor fdobj)使用文件描述符fdobj,创建一个FileInputStream对象,该对象表示到文件系统中某个实际文件的现有连接
  3. FileInputStream(Srting name)打开一个实际文件的连接来创建一个FileInputStream对象,该文件通过文件系统的路径(name)指定

常用方法
close():关闭文件输入流,且释放与此流有关的所有系统资源

read():从该输入流中读取一个字节,如果到达文件末尾返回-1
read(byte[] b):从该输入流中读取b.length个字节存到b数组中,如果到达文件末尾返回-1
read(byte[] b,int off,int len):从该输入流中off处,读取最多len个字节,存入b数组中,如果到达文件末尾返回-1

小练习

要求从D盘中读取test目录下的hello.txt文件(文件里内容是:hello,world),并在控制台输出。
记得关闭流,防止资源浪费。如果不关闭,该流会一直指向该文件资源
使用read(),read(byte[] b),read(byte[] b,int off,int len),三种方法分别实现。

思路分析:
首先创建一个FileInputStream,对象,并让该对象指向hello.txt
然后使用read读取文件,存入程序中的某个属性。
因为一次读取的是一个字节,所以需要遍历读取

代码
第一种:read()

public void readHello1(){//1.创建一个File对象,hello.txt的路径放进去File file = new File("D:\\\\test/hello.txt");FileInputStream fI = null;try {//2.创建一个FileInputStream输入流对象,将路劲给到流,编译异常处理一下fI = new FileInputStream(file);//3.创建循环,使用read方法读取字节,因为读取回来的是数字,所以先用int接受,输出强转成char。int date;while ((date = fI.read())!= -1){//这里表示先把read返回的值给date,然后判断date是不是-1,如果是-1就表示System.out.print((char)date);}} catch (IOException e) {e.printStackTrace();}finally {try {fI.close();} catch (IOException e) {e.printStackTrace();}}}

运行结果:
hello,world

第二种:read(byte[] b)

public void readHello2(){//1.创建一个File对象,hello.txt的路径放进去File file = new File("D:\\\\test/hello.txt");FileInputStream fI = null;try {//2.创建一个FileInputStream输入流对象,将路劲给到流,编译异常处理一下fI = new FileInputStream(file);//3.创建循环,使用read(byte[] b)方法读取字节,存入b数组byte [] b = new byte[20];int readlen = 0;while ((readlen = fI.read(b))!= -1){//这里表示先把read返回的值给date,然后判断date是不是-1,如果是-1就表示System.out.print(new String(b,0,readlen));//从b数组 0 下标处读取readlen个元素拼接成一个String}} catch (IOException e) {e.printStackTrace();}finally {try {fI.close();} catch (IOException e) {e.printStackTrace();}}}

运行结果:
hello,world

第三种
read(byte[] b,int off,int len)

//第三种:read(byte[] b,int off,int len)@Testpublic void readHello3(){//1.创建一个File对象,hello.txt的路径放进去File file = new File("D:\\\\test/hello.txt");FileInputStream fI = null;try {//2.创建一个FileInputStream输入流对象,将路劲给到流,编译异常处理一下fI = new FileInputStream(file);//3.创建循环,使用read(byte[] b,int off,int len)方法读取字节,存入b数组,从文件的0处开始读取,到len处。byte [] b = new byte[20];int readlen = 0;while ((readlen = fI.read(b,0,11))!= -1){//这里表示先把read返回的值给date,然后判断date是不是-1,如果是-1就表示System.out.print(new String(b,0,readlen));//从b数组 0 下标处读取readlen个元素拼接成一个String}} catch (IOException e) {e.printStackTrace();}finally {try {fI.close();} catch (IOException e) {e.printStackTrace();}}}

运行结果:
hello,world

outputStream抽象类

outputStream抽象类是字节输出流基类,用于将程序的数据写出到外部存储容器中。

FileOutputStream类

FileOutputStream类是outputStream的子类,是一个文件输出流

构造器
FileOutputStream(File file):创建一个向指定File对象表示的文件写入数据的文件输出流
FileOutputStream(File file,boolean append):创建一个向指定File对象表示的文件写入数据的文件输出流,(在文件内容后面追加内容)
FileOutputStream(String name):创建一个具有指定name的文件,写入数据的文件输出流
FileOutputStream(String name,boolean append):创建一个具有指定name的文件,写入数据的文件输出流,(在文件内容后面追加内容)

常用方法
close:关闭流
write (int b):将指定字节写入文件输出流

write (byte[] b):将b.length个 字节写入文件输出流

write (byte[] b,int off ,int len ):将b.length个 字节写入文件输出流,从b的off处开始,len处结束

小练习
一:
使用FileOutputStream类,在D盘的txt文件夹中创建a.txt,且添加内容为:hello。

public void m1(){//1.创建FileOutputStream类,并放入 路径和文件名以及类型String fileName = "D:\\\\test/a.txt";FileOutputStream fileOutputStream = null;try {fileOutputStream = new FileOutputStream(fileName);//2.创建文件且写入内容,注意如果发现路径没有该文件,则该方法会自动创建//此方法只能写入一个字节,fileOutputStream.write('H');String s = "heelo";//此方法可以写入一个byte数组,s.getBytes可以将字符串拆分成数组fileOutputStream.write(s.getBytes());//此方法表示写入该数组的从0号下标位置写数组.length个fileOutputStream.write(s.getBytes(),0,s.getBytes().length);} catch (IOException e) {e.printStackTrace();} finally {try {fileOutputStream.close();//关闭流} catch (IOException e) {e.printStackTrace();}}}

二:使用FileInputStream和FileoutputStream配合实现拷贝图片或者音乐
思路:
所有的文件都是二进制的,所以可以创建一个输入流一个输出流,输入流获取原文件,然后再给输出流,输出流负责输出到外部硬盘的指定位置。
注意点:注意文件过大的情况,write方法使用write (byte[] b,int off ,int len )的形式防止文件过大没有读取完整

public void copyFile(){//1.定义原文件的路径和要拷贝到哪里的路径,同时创建输入和输出流String src = "C:\\\\4.jpg";String dest = "D:\\\\test/1.jpg";FileInputStream input = null;FileOutputStream output = null;//2. 定义一个数组保存文件的二进制编码。然后使用循环给输出流byte[] b = new byte[1024];int len = 0;try {input = new FileInputStream(src);output = new FileOutputStream(dest);while ((len = input.read(b))!= -1){output.write(b,0,len);}} catch (IOException e) {e.printStackTrace();}finally {try {input.close();output.close();} catch (IOException e) {e.printStackTrace();}}}

FileReader类和FileWriter类

FileReader类和FileWriter类都是字符流
FileReader类是字符输入流
FileWriter类是字符输出流
IO流基础
IO流基础

FileReader类

文件字符输入流
构造方法
new FileReader(File /String),使用file对象或string对象创建一个输入流

常用方法
read:每次读单个字符,且返回该字符,如果到达文件末尾则返回-1
read(char[]):批量读取多个字符到数组中,返回读取到的字符数,如果到达文件末尾返回-1

相关API
new String(char[]),将一个char数组 ,转换成string
new String(char[],off,len),将char数组的off到len处转换成string

小练习
使用FileRead从story.txt读取内容,并输出打印在控制台

public class FileReader_ {@Testpublic void m1(){String fileName = "D:\\\\test/story.txt";FileReader Fr = null;try {int i = 0;Fr = new FileReader(fileName);while ((i = Fr.read()) != -1){System.out.print((char) i);}} catch (IOException e) {e.printStackTrace();}finally {try {Fr.close();} catch (IOException e) {e.printStackTrace();}}}
}

FileWriter类

文件字符输出流

构造方法
new FileWriter(File /String),使用file对象或string对象创建一个输出流(覆盖模式)
new FileWriter(File /String,true),使用file对象或string对象创建一个输出流,表示在文件末尾追加,而不是覆盖(追加模式)

常用方法
writer(int):写入单个字符
writer(char[]):写入指定数组
writer(char[],off,len):写入指定数组的指定部分
writer(String):写入整个字符串
writer(String,off,len):写入整个字符串的指定部分

相关API
String.toCharArray:将string转换成char[]

注意点
FileWriter使用后必须close或者flush,否则写入不到指定的文件

小练习
使用FileWriter将“风雨之后,定见彩虹”,写入到story.txt文件中(覆盖)

public class FileWriter_ {@Testpublic void m2(){String fileName = "D:\\\\test/story.txt";FileWriter Fw = null;try {Fw = new FileWriter(fileName);Fw.write("风雨之后,定见彩虹");} catch (IOException e) {e.printStackTrace();} finally {try {Fw.close();} catch (IOException e) {e.printStackTrace();}}}
}

节点流和处理流

节点流

节点流可以从一个指定的数据源读/写数据,例如FileReader,FileWriter
节点流只能对单个的数据源进行操作。
节点流不仅有对文件操作的流,还有对数据操作的流,对管道操作的流,等等

IO流基础
IO流基础

处理流

处理流也叫包装流,是“连接”在已存在的流(节点流或处理流)之上。为程序提供更为强大的读写功能。
处理流类在源码中都会维护一个流的基类,例如BufferedReader,里面就维护了一个Reader的属性。BufferedWriter,里面就维护了一个Writer的属性。这样就可以放入它们的子类到处理六中,使之更加的灵活,功能更加的强大
处理流可以抽象的理解为,包裹电线的一层绝缘胶。
现实生活中,让电流正常运输的其实还是里面的导体(节点流),而外面的绝缘胶可以防止漏电,导体破损等功能(处理流)
而在java中,实际干活的是节点流,处理流虽然包裹节点流,但是处理流并不是干活的,他只是为节点流提供服务的。如图所示

IO流基础

处理流类IO流基础

IO流基础
IO流基础

节点流和处理流的区别与联系

  1. 节点流是底层流,是直接跟数据源相接的
  2. 处理流(包装流)会包装节点流,既可以消除不同节点流的实现差,也可以提供更方便的方法来完成输入输出流
  3. 处理流对节点流进行包装,使用了装饰器设计模式,不会直接与数据源相连。

处理流的好处
1.性能的提高:主要以增加缓冲的方式来提高输入输出的效率
2.操作的便捷性:处理流可能提供了一系列便捷的方法来一次输出输出大批量的数据,使用更加灵活方便

修饰器设计模式模拟

下面使用简单的代码来模拟一下修饰器设计模式

public abstract class Reader_ {//基类流public void FileReader(){}public void StringReader(){}
}
class FileReader_ extends Reader_{//节点流@Overridepublic void FileReader() {System.out.println("读取了1次文件");}
}
class StringReader_ extends Reader_{//节点流@Overridepublic void StringReader() {System.out.println("读取了1次字符");}
}
class BufferedReader_ extends Reader_{//处理流Reader_ reader_ ;//维护了一个基类属性public BufferedReader_(Reader_ reader_) {this.reader_ = reader_;}public void FileReaders(int nums) {//在原本的读取上进行扩展,可以读多次for (int i = 0; i < nums; i++) {reader_.FileReader();}}public void StringReaders(int nums) {//在原本的读取上进行扩展,可以读多次for (int i = 0; i < nums; i++) {reader_.StringReader();}}
}
class test{public static void main(String[] args) {FileReader_ fileReader_ = new FileReader_();StringReader_ stringReader_ = new StringReader_();BufferedReader_ bufferedReader_ = new BufferedReader_(fileReader_);bufferedReader_.FileReaders(4);}
}

处理流的缓冲流

在诸多处理流中,有一个非常重要,那就是缓冲流。

我们知道,程序与磁盘的交互相对于内存运算是比较慢的,拖累程序的性能。普通流每次读写一个字节就会向磁盘交互一次,那么减少程序与磁盘的交互,就是提升程序效率一种有效手段。缓冲流,就应用这种思路:缓冲流会在内存中设置一个缓存区,缓冲区先存储足够的待操作数据后,再与内存或磁盘进行交互。这样总体交互的数据量是没有变化的,但是交互的次数减少了,每次交互的数量变多了

处理流(缓冲流):BufferedReader和BufferedWriter

BufferedReader和BufferedWriter是处理流的缓冲流同时也是字符流,所以它们只能负责处理纯文本。不可以处理二进制文件[音频,视频,图片…]

在上面有了解到流在使用完后需要关闭,但是在处理流中实际工作的还是节点流,按照逻辑上来说只需要关闭被处理流包裹的节点流即可。
但是在java中设计了处理流去关闭节点流的形式,所以在使用完处理流后,使用外层流也就是处理流的close方法就可以了,处理流的方法会去关闭节点流的,就不用我们手动去关闭了。

演示使用
使用BufferedReader读取一个纯文本文件,输出在控制台

public class TT1 {public static void main(String [] args)throws Exception{String fileName = "D:\\\\JavaYu\\\\cheek1/BitOperator.java";BufferedReader bufferedReader = new BufferedReader(new FileReader(fileName));String line = "null";while ((line = bufferedReader.readLine())!= null){System.out.println(line);}bufferedReader.close();//}
}

演示使用
使用BufferedWriter在一个一个纯文本文件里写入“hello,world”

public class TT1 {public static void main(String[] args) throws Exception {String fileName = "D:\\\\A.txt";BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(fileName));bufferedWriter.write("hello,world");bufferedWriter.newLine();//换行bufferedWriter.write("hello,world2");bufferedWriter.close();}
}

演示使用
使用BufferedReader和BufferedWriter完成对一个文本文件的拷贝。

public class TT1 {public static void main(String[] args) throws Exception {String srcFileName = "D:\\\\A.txt";String detFileName = "D:\\\\A2.txt";BufferedReader br = new BufferedReader(new FileReader(srcFileName));BufferedWriter bf = new BufferedWriter(new FileWriter(detFileName));String line ;while ((line = br.readLine())!= null){bf.write(line);bf.newLine();}br.close();bf.close();}

处理流(缓冲流):BufferedInputStream和BufferedOutputStream

BufferedInputStream和BufferedOutputStream也是处理流的缓冲流,同时他们也是字节流,用于处理二进制文件

与其他处理流一样,BufferedInputStream和BufferedOutputStream也都各自维护了一个基类的属性,便于处理流操作
BufferedInputStream维护是inputStream
BufferedOutputStream维护的是OutputStream

练习:
要求使用BufferedInputStream和BufferedOutputStream完成对一个图片/视频/音频的拷贝

public static void main(String[] args) {//定义拷贝源路径和目的路径String dirFile = "D:\\\\gugedown/周杰伦 - 我不配.mp3";String srcFile = "D:\\\\gugedown/1.mp3";//定义输入流和输出流BufferedInputStream bis = null;BufferedOutputStream bos = null;//实例化try {bis = new BufferedInputStream(new FileInputStream(dirFile));bos = new BufferedOutputStream(new FileOutputStream(srcFile));//定义一个char数组。一次读取1024个字节byte [] b = new byte[1024];int len= 0;while ((len = bis.read(b))!= -1){bos.write(b,0,len);}System.out.println("拷贝成功");} catch (IOException e) {e.printStackTrace();} finally {try {bis.close();bos.close();} catch (IOException e) {e.printStackTrace();}}}

处理流(对象处理流):ObjectInputStream和ObjectOutputStream

ObjectInputStream和ObjectOutputStream也是处理流,用于处理对象的。
他们提供了对基本类型或对象类型的序列化和反序列化的方法

先看需求:
1.要求将 int a = 100,存储到文件中。要求不仅是存储值,也要存储数据类型。同时可以恢复到程序中
2.要求将Dog dog = new Dog(“小黄”,3)这个对象存储到文件中,且能够恢复

上面的要求就是要求能够将基本数据类型或者对象 进行 序列化反序列化,也叫串行化

什么是序列化和反序列化

  1. 序列化就是在保存数据时,保存数据的值和数据类型
  2. 反序列化就是在回复数据时,恢复数据的值和数据类型
  3. 如果需要让某个对象支持序列化机制,则必须让该类是可序列化的,如此就需要实现下面两个接口的其中一个:
    Serializable接口 — 这是一个标记接口,没有任何内容只是一个空接口
    Externalizable接口

图示:
IO流基础

ObjectInputStream: 提供了反序列化功能,因为是输入流

ObjectOutputStream:提供红了序列化功能,因为是输出流

了解完后我们先用ObjectInputStream来试着将数据使用序列化的方式保存到文件中

public class ObjectInputStream_ {public static void main(String[] args)throws IOException {String fileName = "D:\\\\at.txt";//序列化的文件后缀无所谓//定义一个可序列化的输出流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName));//存点已经实现Serializable接口的基本数据oos.write(100);//会自动转成包装类Integer//注意序列化的基本数据不一样调用的方法也不一样oos.writeUTF("11");oos.writeDouble(1.23);//存一个可序列化的对象oos.writeObject(new Dog("小黄",3));}
}
class Dog implements Serializable {String name;int age;public Dog(String name, int age) {this.name = name;this.age = age;}
}

使用txt文件打开发现是乱码,这是正常的,因为已经不是只存值了,而是连同数据类型一起存了
IO流基础
然后我们再使用ObjectOutputStream读取刚才保存的数据

public void ObjectInputStream_() throws IOException, ClassNotFoundException {String fileName = "D:\\\\at.txt";//序列化的文件后缀无所谓//定义一个输入流ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName));//读取数据,注意读取需要和保存的顺序一致System.out.println(ois.readInt());System.out.println(ois.readUTF());System.out.println(ois.readDouble());Object o = ois.readObject();System.out.println(o);//关闭流ois.close();}

运行结果:
100
11
1.23
Dog{name=‘小黄’, age=3}

对象处理流的注意事项

  1. 读写顺序要一致
  2. 要求序列化或反序列的对象,必须实现Serializable或Externalizable接口
  3. 序列化的类中建议添加SerialVersionUID这个属性,相当于序列号,可以提高兼容性
  4. 序列化对象时,默认将里面所有的属性都进行序列化,除了static和transient修饰的
  5. 序列化对象时,要求将里面所有属性的类型都实现序列化接口(同第一点)
  6. 序列化具可继承性,如果父类实现了Serializable接口,那么子类默认也可进行序列化

标准输入和标准输出

在之前的学习中有用到 System.in和System.out这两个属性

System.in 标准输入 编译类型是inputStream 运行类型 BufferedInputStream默认设备:键盘
System.out 标准输出 编译/运行类型都是 PrintStream 默认设备:显示屏

in和out都是System类中维护的静态属性。

常见用法:
Scanner sc = new Scanner(System.in),传给扫描器,接受键盘输入
System.out.println(“sss”);打印某些内容在显示器上

转换流InputStreamReader和OutputStreamWriter

InputStreamReader和OutputStreamWriter都是字符流,他们有一个功能就是可以将字节流转换成字符流
IO流基础
为什么需要进行转换呢?

首先需要了解一下,字节 有很多编码方式例如 UTF-8 ANSI GBK… 而字符流就没有那么多的编码方式
这就造成一个现象就是字节流可以指定编码方式,字符流不可以指定编码方式。
现在有这么一个例子,一个txt文件里面有“你好sdsdsd”这几个字符,是以UTF-8的编码存储的。
我们用BufferedReader字符流去读取它,显示没有问题。
但是我们改一下文件的编码方式为国标ANSI,再去读取就会发现变成了乱码。
UTF-8
IO流基础
ANSI
IO流基础
这里就引发了一个问题,编码不同会导致乱码。而解决方式就是先用字节流指定编码方式,然后再转换成字符流。

InputStreamReader

使用InputStreamReader解决上面的乱码问题
首先先看一下InputStreamReader的构造器
IO流基础

可以看到InputStreamReader支持将字节流的基类放入,且指定编码。
由此进行一个包装(转换)

练习
将字节流FileInputStream包装(装换成)字符流InputStreamReader对文件进行读取(按照utf-8/gbk格式),再使用BufferedReader读取文本

思路:先将路径放入FileInputStream,然后再将FileInputStream放入InputStreamReader同时指定编码。再将InputStreamReader放入BufferedReader进行读取

public static void main(String[] args) throws IOException {String fileName = "D://a.txt";BufferedReader bf = new BufferedReader(new InputStreamReader(new FileInputStream(fileName),"gbk"));String s = bf.readLine();System.out.println(s);bf.close();}

可以看到就可以成功读取不同编码的文本了,没有乱码
IO流基础

OutputStreamWriter

既然上面有可以读取不同编码的操作,那么OutputStreamWriter自然也可以将不同编码的文本写出到文件中。
下面就使用OutputStreamWriter来写utf-8和gbk两种编码方式的文本到文件中。
首先还是看一下构造器
IO流基础
同样的OutputStreamWriter也可以包装字节输出流的基类同时指定编码

练习
将字节流FileOutputStream包装成(装换成)字符流OutputStreamWriter对文件进行写入(gbk和utf-8)

public static void main(String[] args) throws IOException {String fileName = "d:\\\\b.txt";FileOutputStream fo = new FileOutputStream(fileName);OutputStreamWriter osw = new OutputStreamWriter(fo, "utf8");osw.write("你好,世界");osw.close();}

打印流PrintStream和PrintWriter

PrintStream 字节打印流
PrintWriter 字符打印流

打印流只有输出流没有输入流,一般用于将内容输出到指定的地方,例如控制台,文件中…

PrintStream

PrintStream是字节打印流
IO流基础
IO流基础
可以通过构造方法看出,可以将内容输出到很多地方,而且还可以指定编码

演示使用PrintStream将内容输出到控制台和文件中

public static void main(String[] args) throws IOException {PrintStream out = System.out;//打印到控制台out.print("你好!!!!");out.close();//打印到文件中String fileName = "d:\\\\c.txt";System.setOut(new PrintStream(fileName));System.out.println("你好你好你好");}

PrintWriter

PrintWriter是字符打印流
IO流基础
它同样可以打印内容到不同的地方

演示

public static void main(String[] args) throws IOException {//打印到控制台PrintWriter printWriter = new PrintWriter(System.out);printWriter.print("didiid");printWriter.close();//打印到文件PrintWriter printWriter1 = new PrintWriter("d:\\\\c.txt");printWriter1.print("hahhah");printWriter1.close();}

Properties类

在实际开发中可能会用到很多的配置文件,例如需要获取配置文件中的IP,user,pwd。
使用传统方法读取数据是这样的。

public static void main(String[] args) throws IOException {String fileName = "src\\\\properties";BufferedReader bf = new BufferedReader(new FileReader(fileName));String len = " ";while ((len = bf.readLine())!= null){System.out.println(len);}}

但是这样的话比较麻烦,如果要改动的什么的就需要去改动源码,不灵活

Properties介绍

Properties是一个专门用于读取配置文件的集合类
配置文件的格式:
键 = 值
键 = 值
注意键值对不需要空格,也不用双引号包裹,默认是String类型

Properties的常用方法
load:加载配置文件的键值对到Properties对象
list:将数据显示到指定设备
getProperty(key):根据键获取值
setProperty(key,value):根据键修改值,如果没有键就添加。
store:将Properties对象中的键值对存储到配置文件中,如果含有中文则以unicode码存储

演示使用Properties类对配置文件进行读取和修改

public static void main(String[] args) throws IOException {String fileName = "src\\\\properties";Properties properties = new Properties();//先将配置文件加载到Properties对象中properties.load(new FileReader(fileName));//读取全部配置文件的数据properties.list(System.out);//根据键查找值System.out.println("IP是"+properties.getProperty("ip"));//根据键修改值properties.setProperty("pwd","999");System.out.println(properties.getProperty("pwd"));}

演示使用Properties类将配置数据保存到新的配置文件

public void test7() throws IOException{String fileName = "src\\\\properties2";Properties properties = new Properties();properties.setProperty("charset","gbk");properties.setProperty("user","嗡嗡嗡");properties.setProperty("pwd","9090");properties.store(new FileWriter(fileName),"这里可以写注释");}

IO练习

一:编程题
1)判断D盘下有没有文件夹mytemp,如果没有就创建
2)在D:\\mytemp目录下,创建文件hello.txt
3)如果hello.txt已经存在。提示该文件存在,就不要重复创建了
4) 并且在hello.txt写入hello.world

public static void main(String[] args) throws IOException {//定义文件夹的路径String filePath = "d:\\\\mytemp";//创建File对象,判断该文件是否存在File file = new File(filePath);if (!file.exists()){//如果不存在就创建if (file.mkdirs()){//创建成功就提示创建成功System.out.println("创建文件夹成功");}else{System.out.println("创建失败");}}else{//如果存在就提示不需要创建System.out.println("已经存在不需要创建");}//定义hello.txt的路径String fileName = "D:\\\\mytemp/hello.txt";//判断该文件是否已经存在File file1 = new File(fileName);if(file1.exists()){//如果存在就提示已经存在System.out.println("hello.txt,已存在不需要创建");}else{//如果不存在就创建且写入内容file1.createNewFile();//创建输出流写出FileWriter fileWriter = new FileWriter(file1);fileWriter.write("hello.word1");fileWriter.close();}}

二:编程题
使用BufferedReader读取一个文本文件,为每行加上行号,连同内容一起输出在屏幕上

public static void main(String[] args) throws IOException {String fileName = "d:\\\\mytemp/hello.txt";BufferedReader bf = new BufferedReader(new FileReader(fileName));String len = null;int num = 0;while ((len = bf.readLine())!= null){System.out.println(++num +len);}bf.close();}

如果改变了文本的编码,就需要用到转换流。

public class test2 {public static void main(String[] args) throws IOException {String fileName = "d:\\\\mytemp/hello.txt";FileInputStream fr = new FileInputStream(fileName);InputStreamReader isr = new InputStreamReader(fr,"gbk");BufferedReader bf = new BufferedReader(isr);String len = null;int num = 0;while ((len = bf.readLine())!=null){System.out.println(++num + len);}bf.close();fr.close();}
}

三:编程题
1编写一个dog.properties配置文件
name=tom
age=5
color=red
2编写Dog类(name,age,color)创建一个dog对象,读取dog配置文件用相应的内容完成初始化,并输出
3创建完成后将改对象序列化保存到d:\\mytemp文件中,然后反序列化读取输出

public class test3 {public static void main(String[] args) throws IOException, ClassCastException, ClassNotFoundException {String fileName = "src\\\\dog";Properties p = new Properties();p.setProperty("name","tom");p.setProperty("age","5");p.setProperty("color","red");p.store(new FileWriter(fileName),null);Dog dog = null;String name1 = p.getProperty("name");int age1 = Integer.parseInt(p.getProperty("age"));String color1= p.getProperty("color");dog = new Dog(name1,age1,color1);System.out.println(dog);//序列化ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:\\\\mytemp/dog.date"));oos.writeObject(dog);oos.close();//反序列化ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:\\\\mytemp/dog.date"));Dog d2 = (Dog) ois.readObject();System.out.println(d2);ois.close();}
}
class Dog implements Serializable {String name;int age;String color;public Dog(String name, int age, String color) {this.name = name;this.age = age;this.color = color;}@Overridepublic String toString() {return "Dog{" +"name='" + name + '\\'' +", age=" + age +", color='" + color + '\\'' +'}';}
}