IO流

IO概述
Java IO即Java 输入输出系统。不管我们编写何种应用,都难免和各种输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,这要考虑的因素特别多,比如我们要考虑和哪种媒介进行IO(文件、控制台、网络等等),我们还要考虑具体和它们的通信方式(顺序、随机、二进制、按字符、按字、按行等等)。Java类库的设计者通过设计大量的类来攻克这些难题,这些类就位于java.io包中。
在JDK1.4之后,为了提高Java IO的效率,Java又提供了一套新的IO,Java New IO简称Java NIO。它在标准java代码中提供了高速的面向块的IO操作。
2.流
在Java IO中,流是一个核心的概念。流从概念上来说是一个连续的数据流。你既可以从流中读取数据,也可以往流中写数据。流与数据源或者数据流向的媒介相关联。在Java IO中流既可以是字节流(以字节为单位进行读写),也可以是字符流(以字符为单位进行读写)。在JAVA中把不同的输入/输出源(键盘、文件、网络等)抽象表述为“流”。

根据针对数据类型的处理,分为字节流和字符流:

  1. 字节流中包含输入流【InputStream】和输出流【OutputStream】两种情况,在
    在Java中,InputStream和OutputStream是java.io包中所有字节流API类的基类。

  2. 字符流中包含输入流【Reader】和输出【Writer】两种情况,
    在Java中,Reader和Writer是java.io包中所有字符流API类的基类。

2.1API规律
由这四个抽象类派生出来的子类的名称是以其抽象父类名称为后缀,以功能为前缀。所以判定某一个具体的流的父类,就找出它的结尾的类名是什么,它的抽象父类就是什么。

e.g. 一个类的名字叫FileInputStream,它是以InputStream为结尾的,所以这个FileInputStream的抽象父类就是InputStream类。这个类的功能从前缀进行判断。由于前缀是File,所以这个类的功能是用用于处理文件的字节输入流。
2.2IO流秘史
Java中操纵数据的方式都是通过流的方式,早期的Java的IO包中都是字节流(体现均为二进制字节)

字符流是从字节流中分离出来的,用来处理文本数据的流。

字符流产生的背景:

  1. 相同的字符到不同的编码表中对应的二进制数字 (也就是码值) 不一样。
  2. 所以相同的码值 (实际为二进制数字) 对应到不同的码表可能会因为某个码表不存在该码值而出现查找不到对应字符的情况,这样就会出现乱码。

字符流的诞生:
为了解决乱码的问题,Java在字节流的基础上融合了编码表,从而产生了字符流。这样使用字符流直接处理文本数据是非常方便的。
字节流是通用的,字符流是基于字节流的。
4.File类
写在学习之前,在之前我们操作系统中的文件都是通过可视化界面,接下来关于IO学习中的示例,是使用代码去针对文件进行操作
4.1File类构造函数
4.2API
File(String pathname)
根据一个路径得到File对象
File(String parent, String child)
根据一个目录和一个子文件/目录得到File对象
File(File parent, String child)
根据一个父File对象和一个子文件/目录得到File对象
4.3代码示例
需求:创建一个File类型对象,路径分为相对路径和绝对路径,判断该对象对应的文件/路径在电脑中是否存在
exists()用于判断File对象是否存在
File f1 = new File(相对路径/绝对路径);
System.out.println(f1.exists());

File f2 = new File(父路径,子路径/文件名);
System.out.println(f2.exists());

File f3 = new File(File类型对象,子路径/文件名);
System.out.println(f3.exists());

5.File类的创建功能
5.1API
boolean mkdir()
创建文件夹,如果存在这样的文件夹,就不创建了,路径不存在返回flase
boolean mkdirs()
创建文件夹,如果父文件夹不存在,会帮你创建出来
boolean createNewFile()
创建文件,路径不存在抛出异常,如果存在这样的文件,就不创建了
5.2代码示例
注意事项:若创建文件或者文件夹忘了写盘符路径,那么默认在项目路径下
需求:指定路径的File对象,mkdir创建文件夹,路径存在和路径不存在

需求:指定路径的File对象,mkdirs创建文件夹,路径存在和路径不存在

需求:指定路径的File对象,createNewFile创建文件,路径存在和路径不存在

6.File类的获取功能API
String getAbsolutePath()
获取文件的绝对路径
File getAbsoluteFile()
获取文件的绝对路径
String getPath()
获取文件的相对路径
String getName()
获取名称
String[] list()
获取指定目录下的所有文件或者文件夹的名称数组
File[] listFiles()
获取指定目录下的所有文件或者文件夹的File数组
File[] listRoots()
获取电脑中的盘符
String[] list (FilenameFilter filter)
获取指定目录下被FilenameFilter筛选后的文件,返回String类型数组
注意:FilenameFilter实现类中的accept(File file,String name)中两个参数,第一个参数为File对象可以表示为一个路径,第二个参数为该路径下的文件名
File[] list (FilenameFilter filter)
获取指定目录下被FilenameFilter筛选后的文件,返回String类型数组
File[] listFiles (FileFilter filter)
获取指定目录下被FileFilter筛选后的文件,返回File类型数组
注意:FileFilter实现类中的accept(File file)只有一个参数,该参数指代的是一个文件的路径,和FilenameFilter中的区别在于,FilenameFilter中两个参数合在一起才能指定一个文件,而FileFilter则没有将路径和文件名分开,通过观察两个接口的名称也能看出二者的区别

递归
从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故事:从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故事:从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故事:……

递归:本质上就是方法自己调用自己
递归中处理的代码逻辑实质上是一样的,所以可以实现自己调用自己 ,但是递归不能无限制去调用,因为递归调用是无限次调用,而电脑内存是有限的,所以递归的使用需要慎重

代码示例
【演示】main方法自己调自己,出现的异常,截图

【练习】斐波拉契数列,假设有函数f(x)且f(0)=0、f(1)=1,第x个值公式为f(x)=f(x-1)+f(x-2),根据以上给出的条件实现x为任意数时的值的代码实现
public static int f(int x){
if (x == 0) {
return 0;
}else if (x == 1) {
return 1;
}
return f(x-1)+f(x-2);
}

Day23 Java IO-2

节点流:又叫低级流
处理流:高级流

字节流和字符流的区别在于数据处理单位的不同。
字节流:一次读或写8位二进制。字节流关于输入和输出的基类有两个。

字符流:一次读或写16位二进制。字符流关于输入和输出的基类有两个

【扩展知识点】
节点流:程序直接连接到实际的数据源,进行读写。
从/向一个特定的I/0设备(磁盘、网络等)读写数据的流称为节点流,也常被称为低级流。

处理流:又称高级流或包装流,处理流对一个已存在的节点流进行连接,通过封装后的流来进行读写。

Java使用处理流来包装节点流是一种典型的装饰器设计模式。
处理流则对于一个已存在的节点流进行连接或封装,常被称为高级流(装饰器设计模式)。

Java中操作流的类分类
整体API分类:

按照功能进行API分类:

访问文件
2.字节流
2.1字节输入流【FileInputStream】
字节输入流读取文件的实现步骤:

  1. 关联实体文件,创建FileInputStream对象

  2. 调用read方法

  3. 关闭输入流【close】
    API

  4. 字节输入流对象,使用构造函数:
    FileInputStream(File file)
    返回一个字节输入流对象,该对象使用字节流读取文件,参数为File类型关联实体文件
    FileInputStream(String name)
    返回一个字节输入流对象,传入的name为路径+文件名

  5. 使用字节输入流对象读取文件:
    字节输入流对象在读取到最终的数据结尾时,返回-1
    int read()
    单字节读取文件,返回读取的下一次的数据字节数,若下一次读取没有数据则返回为-1
    int read(byte[] b)
    多字节读取文件,读取指定数组长度的数据字节,若下一次读取没有数据则返回为-1
    多字节读取时,使用byte类型的数组作为缓冲区,可能会存在数据重复问题
    int read(byte[] b,int off,int len)
    多字节读取文件,读取指定数组长度的数据字节,若下一次读取没有数据则返回为-1
    参数2和参数3是针对数组缓冲区进行的设置
    参数off:从缓冲区数组第几个下标开始读取
    参数len:从缓冲区数组中读取指定长度的数据
    注意:参数2和参数3相加的值不能大于等于数组的长度,否则会引发下标异常

  6. 关闭输入流对象
    void close()
    关闭输入流对象
    代码示例
    单个字节读取
    FileInputStream inputStream = new FileInputStream(new File
    (“D:/work/STS/JavaSE-Day24-IO/1.txt”));

//System.out.println(inputStream.read());
//System.out.println((char)inputStream.read());

//循环遍历读取数据
int n;
while ((n=inputStream.read())!=-1) {
System.out.println((char)n);
}
//关闭输入流
inputStream.close();
多个字节读取,采用byte类型数组为缓冲区,若缓冲区不能被数据长度整除则可能造成数据重复输出
FileInputStream inputStream = new FileInputStream
(“D:/work/STS/JavaSE-Day24-IO/1.txt”);
byte[] b=new byte[4];

//将字节数组打印输出
for (byte c : b) {
System.out.println((char)c);
}
int n;
while ((n=inputStream.read(b))!=-1) {
System.out.println(new String(b));
}
//关闭输入流
inputStream.close();
多个字节读取,解决数据重复问题
FileInputStream inputStream = new FileInputStream
(“D:/work/STS/JavaSE-Day24-IO/1.txt”);

// 定义读取数据的缓冲区
byte[] b = new byte[4];

//循环读取并输出
int n;
while ((n = inputStream.read(b)) != -1) {
System.out.println(new String(b,0,n));
}
//关闭输入流
inputStream.close();
多个字节读取,对数组缓冲区进行设置
使用read(byte[] b,int off,int len)
参数2和参数3是针对缓冲区进行设置,相加的值不能大于等于数组长度
FileInputStream inputStream = new FileInputStream
(“D:/work/STS/JavaSE-Day24-IO/1.txt”);

// 定义读取数据的缓冲区
byte[] b = new byte[4];

//循环读取并输出
int n=0;
while ((n = inputStream.read(b,1,2)) != -1) {
System.out.println(new String(b));
}
//关闭输入流
inputStream.close();
2.2字节输出流【FileOutputStream】
字节流输出数据的代码实现步骤:

  1. 关联实体文件,创建输出流对象
  2. 调用write方法
  3. 关闭输出流
    API
  4. 字节输出流对象,构造函数:
    FileOutputStream(File file)
    返回一个字节输出流对象,参数为File类型关联实体文件
    FileOutputStream(String name)
    返回一个字节输出流对象,参数为String类型,取值为路径+文件名

向文件中设置是否追加数据:
FileOutputStream(File file, boolean append)
返回一个字节输出流对象,参数1File类型关联实体文件,参数2布尔值true代表追加
FileOutputStream(String name, boolean append)
返回一个字节输出流对象,参数1String类型关联实体文件,参数2布尔值true代表追加
2. 字节输出流对象输出数据到指定文件:
注意:
如果输出的路径不存在会抛出异常,如果输出的路径存在而文件不存在则会创建新的文件
如果不需要对输出的文件进行追加效果,那么需要在创建输出流对象的时候添加布尔值

void write(int b)
将指定字节写入文件输出流中
void write(byte[] b)
将指定的byte数组中的数据写入到文件
void write(byte[] b,int off,int len)
将指定byte数组中的数据指定起始位置和长度的数据输出到文件中
3. 关闭字节输出流对象:
void close()
关闭文件输出流
代码示例
注意事项:
如果输出的文件路径不存在,则抛出异常
如果输出的文件不存在,则自动创建新的文件
如果输出流对象没有设置追加,且输出路径和文件是一致的,则会覆盖前次的输出内容
使用FileOutputStream(File file)创建对象输出数据到文件:
FileOutputStream fos = new FileOutputStream
(new File(“D:/work/STS/JavaSE-Day24-IO/2.txt”));
fos.write(97); //97 是ASCII码值,文件中写入的是a
fos.close();
使用FileOutputStream(String name)创建对象输出数据到文件:
FileOutputStream fos = new FileOutputStream
(“D:/work/STS/JavaSE-Day24-IO/2.txt”);
byte[] b=“abcdefghijk”.getBytes();
fos.write(b); //传入的是一个byte类型的数组
fos.close();
FileOutputStream(File file,boolean append)创建追加输出流对象:
FileOutputStream fos = new FileOutputStream
(“D:/work/STS/JavaSE-Day24-IO/2.txt”,true);
byte[] b=“0123456789”.getBytes();
fos.write(b, 2, 6);
fos.close();
FileOutputStream(String name,Boolean append)创建追加输出流对象:
FileOutputStream fos = new FileOutputStream
(“D:/work/STS/JavaSE-Day24-IO/2.txt”, true);
byte[] b=“0123456789”.getBytes();
fos.write(b, 2, 2);
fos.close();
3.字符流
3.1字符输入流【FileReader】
字符输入流读取文件的实现步骤:

  1. 关联实体文件,创建FileReader对象

  2. 调用read方法

  3. 关闭输入流【close】
    API

  4. 字符输入流对象,使用构造函数:
    FileReader(File file)
    返回一个字符输入流对象,该对象使用字符流读取文件,参数为File类型关联实体文件
    FileReader(String name)
    返回一个字符输入流对象,传入的name为路径+文件名

  5. 使用字符输入流对象读取文件:
    字符输入流对象在读取到最终的数据结尾时,返回-1
    int read()
    单字符读取文件,返回读取的下一次的数据字符数,若下一次读取没有数据则返回为-1
    int read(char[] c)
    多字符读取文件,读取指定数组长度的数据字符,若下一次读取没有数据则返回为-1
    多字符读取时,使用byte类型的数组作为缓冲区,可能会存在数据重复问题
    int read(char[] c,int off,int len)
    多字符读取文件,读取指定数组长度的数据字符,若下一次读取没有数据则返回为-1
    参数2和参数3是针对数组缓冲区进行的设置
    参数off:从缓冲区数组第几个下标开始读取
    参数len:从缓冲区数组中读取指定长度的数据
    注意:参数2和参数3相加的值不能大于等于数组的长度,否则会引发下标异常

  6. 关闭输入流对象
    void close()
    关闭输入流对象
    代码示例
    单个字符读取
    FileReader fr = new FileReader(new File
    (“D:/work/STS/JavaSE-Day24-IO/1.txt”));

//System.out.println(fr.read());

//循环遍历读取数据
int n;
while ((n=fr.read())!=-1) {
System.out.println((char)n);
}
//关闭输入流
fr.close();
多个字节读取,采用byte类型数组为缓冲区,若缓冲区不能被数据长度整除则可能造成数据重复输出
FileReader fr = new FileReader(“D:/work/STS/JavaSE-Day24-IO/1.txt”);
char[] c=new char[4];

//将字节数组打印输出
for (char c : b) {
System.out.println((char)c);
}
int n;
while ((n=fr.read(b))!=-1) {
System.out.println©;
}
//关闭输入流
fr.close();
多个字节读取,对数组缓冲区进行设置
使用read(char[] c,int off,int len)
参数2和参数3是针对缓冲区进行设置,相加的值不能大于等于数组长度
FileReader fr = new FileReader(“D:/work/STS/JavaSE-Day24-IO/1.txt”);

// 定义读取数据的缓冲区
char[] b = new char[4];

//循环读取并输出
int n=0;
while ((n = fr.read(c,1,2)) != -1) {
System.out.println©;
}
//关闭输入流
fr.close();
3.2字符输出流【FileWriter】
字符流输出数据的代码实现步骤:

  1. 关联实体文件,创建输出流对象
  2. 调用write方法
  3. 关闭输出流
    API
  4. 字符输出流对象,构造函数:
    FileWriter(File file)
    返回一个字符输出流对象,参数为File类型关联实体文件
    FileWriter(String name)
    返回一个字符输出流对象,参数为String类型,取值为路径+文件名

向文件中设置是否追加数据:
FileWriter(File file, boolean append)
返回一个字符输出流对象,参数1File类型关联实体文件,参数2布尔值true代表追加
FileWriter(String name, boolean append)
返回一个字符输出流对象,参数1String类型关联实体文件,参数2布尔值true代表追加
2. 字符输出流对象输出数据到指定文件:
注意:
如果输出的路径不存在会抛出异常,如果输出的路径存在而文件不存在则会创建新的文件
如果不需要对输出的文件进行追加效果,那么需要在创建输出流对象的时候添加布尔值

void write(int b)
将指定字符写入文件输出流中
void write(char[] c)
将指定的char数组中的数据写入到文件
void write(char[] c,int off,int len)
将指定char数组中的数据指定起始位置和长度的数据输出到文件中
void write(String str)
将字符串输出到指定的文件中
void write(String str,int off,int len)
指定字符串的起始位置和长度,输出到指定的文件中
3. 关闭字节输出流对象:
void close()
关闭文件输出流
代码示例
注意事项:
如果输出的文件路径不存在,则抛出异常
如果输出的文件不存在,则自动创建新的文件
如果输出流对象没有设置追加,且输出路径和文件是一致的,则会覆盖前次的输出内容
使用FileWriter(File file)创建对象输出数据到文件:
FileWriter fw = new FileWriter
(new File(“D:/work/STS/JavaSE-Day24-IO/2.txt”));
fw.write(97); //97 是ASCII码值,文件中写入的是a
fw.close();
使用FileWriter(String name)创建对象输出数据到文件:
FileWriter fw = new FileWriter(“D:/work/STS/JavaSE-Day24-IO/2.txt”);
char[] c={‘我’,‘你’};
fw.write©; //传入的是一个char类型的数组
fw.close();
FileWriter(File file,boolean append)创建追加输出流对象:
FileWriter fw = new FileWriter
(new File(“D:/work/STS/JavaSE-Day24-IO/2.txt”),true);
char[] c={‘我’,‘你’};
fw.write(c, 0, 1);
fw.close();
FileWriter(String name,Boolean append)创建追加输出流对象:
FileWriter fos = new FileWriter(“D:/work/STS/JavaSE-Day24-IO/2.txt”, true);
char[] c={‘我’,‘你’};
fw.write(c, 0, 1);
fw.close();
直接将字符串输出到文件中
FileWriter fw = new FileWriter(“D:/work/STS/JavaSE-Day24-IO/2.txt”,true);
fw.write(“今晚小树林”);
fw.close();

4.转换流
电脑中任何数据都是以二进制形式存在的,文件被读取显示通过字节流读取然后转换为字符流显示,若需要将数据写入文件中,那么数据最终在文件中写入的是二进制形式,所以可以显示指定二进制流关联文件,字符流转换为字节流
4.1字节流转字符流【InputStreamReader】
字节流转成字符流的步骤:

  1. 准备一个字节流
  2. 将字节流转成字符流输出
  3. 关闭流
    API

将字节流转换为字符流,使用InputStreamReader构造函数
InputStreamReader(InputStream in)
将字节流对象包装成一个InputStreamReader对象,默认使用本机字符编码
InputStreamReader(InputStream in,String charset)
将字节流对象包装成一个InputStreamReader对象,使用指定的编码格式
代码示例
先使用字节流读取包含中文的文件并输出
FileInputStream fis = new FileInputStream
(“D:/work/STS/JavaSE-Day24-IO/src/cn/itsource/readerandwriter/ReaderAndWriterTest.java”);

byte[] b=new byte[4];
int len;

StringBuilder build=new StringBuilder();
while ((len=fis.read(b))!=-1) {
build.append(new String(b));
}

System.out.println(build.toString());
fis.close();
优化字节流读取文件时可能出现的乱码问题
FileInputStream fis = new FileInputStream
(“D:/work/STS/JavaSE-Day24-IO/src/cn/itsource/readerandwriter/ReaderAndWriterTest.java”);

//将字节流包装为字符流
InputStreamReader isr = new InputStreamReader(fis);
char[] c=new char[4];
int len;

StringBuilder build=new StringBuilder();
while ((len=isr.read©)!=-1) {
build.append(new String©);
}
System.out.println(build.toString());
isr.close();
fis.close();

4.2字符流转字节流【OutputStreamWriter】
字符流转字节流步骤:

  1. 准备一个字符流
  2. 将字符流转换为字节流
  3. 关闭流
    API
    将字符流转换为字节流
    OutputStreamWriter(OutputStream out)
    将一个字符流中的数据内容写入到转换为显示指定的字节流对象
    OutputStreamWriter(OutputStream out,String charset)
    使用指定的编码格式将字符流转换为字节流
    代码示例
    字符流输出数据到文件中,使用字节流关联文件
    FileOutputStream fos = new FileOutputStream
    (“D:/work/STS/JavaSE-Day24-IO/5.txt”); //字节流关联实体文件

OutputStreamWriter osw = new OutputStreamWriter(fos); //字符流输出
osw.write(“输出中文”);

osw.close();
fos.close();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值