I/O流
IO概述
IO:输入输出(input/output) 流:一种抽象概念,是对数据传输的总称,也就是说数据在设备间的传输称为流,流的本质是数据传输 IO流就是用来处理设备间数据传输问题的 常见的应用:文件复制、文件上传、文件下载
IO流分类
按照输入的流向
按照数据类型来分
- 字节流:字节输入流、字节输出流
- 字符流:字符输入流、字符输出流
一般来说,我们说IO流的分类是按照数据类型来分的 如果数据通过Windows自带的笔记本软件打开,我们还可以读懂里面的内容,就使用字符流。否则使用字节流。 如果不知道该使用哪种类型的流,就使用字节流。
File类
他是文件和目录路径名的抽象表示 文件和目录是可以通过File封装成对象的 对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已,它可以是存在的,也可以是不存在的,将来是要通过具体的操作把这个路径的内容转换为具体存在的。
绝对路径和相对路径的区别
绝对路径:完整的路径名,不需要其他信息就可以定位它所表示的文件,例如:E:\itcast\java.txt 相对路径:必须使用取自其他路径名的信息进行解释,例如:myFile\java.txt
构造方法
方法名 | 说明 |
---|
File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例 | File(String parent,String child) | 从父路径名字符串和子路径名字符串创建新的File实例 | File(File parent,String child) | 从父抽象路径名和子路径名字符串创建新的File实例 |
File file=new File("E:\\IOTest\\01.txt");
System.out.println(file);
File file2=new File("E:\\IOTest","01.txt");
System.out.println(file2);
File file3=new File("E:\\IOTest");
File file4=new File(file3,"01.txt");
System.out.println(file4);
创建功能
方法名 | 说明 |
---|
public boolean createNewFile() | 当具有该名称的文件不存在时,创建一个由该抽象路径命名的新空文件 | public boolean mkdir() | 创建由此抽象路径命名的目录 | public boolean mkdirs() | 创建由此抽象路径命名的目录,包括任何必须但不存在的父目录 |
File file=new File("E:\\IOTest\\01.txt");
file.createNewFile();
File file2=new File("E:\\IOTest\\JavaSE");
file2.mkdir();
File file3=new File("E:\\IOTest\\JavaWeb\\HTML");
file3.mkdirs();
File类判断、获取和删除功能
方法名 | 说明 |
---|
public boolean isDirectory() | 测试此抽象路径表示的File是否为目录 | public boolean isFile() | 测试此抽象路径名表示的File是否为文件 | public boolean exists() | 测试此抽象路径表示的File是否存在 | public String getAbsolutePath() | 返回此抽象路径名的绝对路径名字符串 | public String getPath() | 将此抽象路径名转换为路径名字符串 | public String getName() | 发挥由此抽象路径名表示的文件或目录的名称 | public String[] list() | 返回此抽象路径名表示的目录中文件和目录的名称字符串数组 | public file[] listFiles() | 返回由此抽象路径名表示的目录中的文件和目录的File对象数组 | public boolean delete() | 删除由此抽象路径名表示的文件或目录 |
File file=new File("E:\\IOTest");
boolean flag=file.isDirectory();
System.out.println(flag);
flag=file.isFile();
System.out.println(flag);
flag=file.exists();
System.out.println(flag);
String string=file.getAbsolutePath();
System.out.println(string);
string=file.getPath();
System.out.println(string);
string=file.getName();
System.out.println(string);
String[] arr=file.list();
for (String string2 : arr) {
System.out.println(string2);
}
File[] files=file.listFiles();
for (File file2 : files) {
System.out.println(file2);
}
flag=file.delete();
System.out.println(flag);
遍历目录
给定一个路径E:\IOTest,请通过递归方式遍历目录,并把所有文件的绝对路径输出在控制台。
public static void main(String[] args) {
File file=new File("E:\\IOTest");
show(file);
}
public static void show(File file) {
File[] fileArray=file.listFiles();
if (fileArray!=null) {
for (File f : fileArray) {
if (f.isDirectory()) {
show(f);
}else {
System.out.println(file.getAbsolutePath());
}
}
}
}
字节流
字节流写数据
字节流抽象基类 InputStream:这个抽象类表示字节输入流的所有类的超类 OutStream:这个抽象类是表示字节输出流的所有类的超类 子类名的特点:子类名称都是以其父类名作为子类名的后缀
FileOutputStream fos=new FileOutputStream("E:\\IOTest\\01.txt");
fos.write(97);
fos.write(57);
fos.close();
字节流写数据的三种方式
方法名 | 说明 |
---|
void write() | 将指定的字节写入此文件输出流,一次写一个字节数据 | void write() | 将b.lengh字节从指定的字节数组写入输出流,一次写入一个字节数组数据 | void write(byte[] b,int off,int len) | 将len字节从指定的字节数组开始,从偏移量off开始写入次文件输出流,一次写入一个字节数组的部分数据 |
FileOutputStream fos=new FileOutputStream("E:\\IOTest\\01.txt");
fos.write(97);
fos.write(98);
fos.write(99);
fos.write(100);
fos.write(101);
byte[] bys= {97,98,99,100,101};
fos.write(bys);
byte[] bys="abcdefg".getBytes();
fos.write(bys);
byte[] bys="abcdefg".getBytes();
fos.write(bys,0,3);
fos.close();
字节流写数据的两个问题
字节流写数据如何实现换行 写完数据后,增加换行符
FileOutputStream fos=new FileOutputStream("E:\\IOTest\\01.txt");
for (int i = 0; i <10; i++) {
fos.write("hello".getBytes());
fos.write("\n".getBytes());
}
字节流写数据如何实现追加写入 public FileOutputStream(String name,boolean append); 创建文件输出流以指定的名称写入文件,如果第二个参数为true,则字节将写入文件末尾而不是开头
FileOutputStream fos2=new FileOutputStream("E:\\IOTest\\01.txt",true);
for (int i = 0; i <2; i++) {
fos.write("true".getBytes());
fos.write("\n".getBytes());
}
fos.close();
字节流写数据加异常处理
finally:在异常处理时提供finally块来执行所有清除操作,比如IO流中的释放资源 特点:被finally控制的语句一定会执行,除非JVM退出
try {
FileOutputStream fos=new FileOutputStream("E:\\IOTest\\01.txt");
for (int i = 0; i <3; i++) {
fos.write("hello".getBytes());
fos.write("\n".getBytes());
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
FileOutputStream fos=null;
try {
fos=new FileOutputStream("E:\\IOTest\\01.txt");
for (int i = 0; i <3; i++) {
fos.write("hello".getBytes());
fos.write("\n".getBytes());
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fos!=null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字节流读数据
一次读一个字节数据
需求:把文件01.txt中的内容度祛除了在控制台输出
FileInputStream(String name),通过代开与实际文件的连接来创建一个FileInputStream,该文件由文件系统的路径名name命名
使用字节输入流读数据的步骤
- 创建字节输入流对象
- 调用字节输入流对象读数据的方法
- 释放资源
File file=new File("E:\\IOTest\\01.txt");
FileInputStream fis=new FileInputStream(file);
int by;
while ((by=fis.read())!=-1) {
System.out.print((char)by);
}
fis.close();
案例:复制文本文件
把E:\IOTest\01.txt复制到目录下02.txt
分析
- 复制文本文件,其实就是把文本文件的内容从一个文件中读取出来(数据源),然后写入到另一个文件中去(目的地)
- 数据源E:\IOTest\01.txt— 读数据—InputStream—FileInputStream
- 目的地:02.txt—写数据—OutputStream—FileOutStream
思路
- 根据数据源创建字节输入流对象
- 根据目的地创建字节输出流对象
- 读写数据,复制文本文件(一次读取一个字节,一次写入一个字节)
- 释放资源
File file=new File("E:\\IOTest\\01.txt");
File file2=new File("E:\\IOTest\\02.txt");
FileInputStream fis=new FileInputStream(file);
FileOutputStream fos=new FileOutputStream(file2);
int by;
while ((by=fis.read())!=-1) {
fos.write(by);
}
fis.close();
fos.close();
一次读一个字节数组数据
使用字节输入流读数据的步骤
- 调用字节输入流对象
- 调用字节输入流对象的读取方法
- 释放资源
File file=new File("E:\\IOTest\\01.txt");
FileInputStream fis=new FileInputStream(file);
byte[] by =new byte[1024];
int len;
while ((len=fis.read(by))!=-1) {
System.out.print(new String(by,0,len));
}
fis.close();
案例:复制图片
把E:\IOTest\01.jpg复制到目录下02.jpg
思路
- 根据数据源创建字节输入流对象
- 根据目的地创建字节输出流对象
- 读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
- 释放资源
FileInputStream fis=new FileInputStream("E:\\IOTest\\01.jpg");
FileOutputStream fos=new FileOutputStream("E:\\IOTest\\02.jpg");
byte[] bys=new byte[1024];
int len;
while ((len=fis.read(bys))!=-1) {
fos.write(bys,0,len);
}
fis.close();
fos.close();
字节缓冲流
BufferOutputStream 该类实现缓冲输出流,通过设置这样的输出流,应用程序可以向底层暑促会写入字节,而不必为了写入每个字节导致底层系统的调用 BufferedOutputStream 创建BufferedInputStream将创建一个内部缓冲区数组,当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节。
构造方法
字节缓冲输出流:BufferedOutputStream(OutputStream out) 字节缓冲输入流: BufferedInputStream(InputStream in)
为什么构造方法需要的是字节流,而不是具体的文件或者路径? 因为字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作
BufferedOutputStream bfos=new BufferedOutputStream(new FileOutputStream("E:\\IOTest\\02.txt"));
bfos.write("hello world\r\n".getBytes());
bfos.close();
BufferedInputStream bfis=new BufferedInputStream(new FileInputStream("E:\\IOTest\\02.txt"));
int by;
while ((by=bfis.read())!=-1) {
System.out.print((char)by);
}
byte[] bys=new byte[1024];
int len;
while ((len=bfis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
}
bfis.close();
字符流
一个汉字存储: 如果是GBK编码,占用两个字节 如果是UTF-8编码,占用3个字节
汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数 字符流=字节流+编码表
编码表
计算机中存储的信息都是用二进制数表示的,我们在屏幕上看到的英文、汉字等字符是二进制转换之后的结果。 按照某种规则,将字符存储到计算机汇总,称为编码。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码。 按照A编码存储,必须按照A编码解析,这样才能显示正确的文本符号,否则就会导致乱码现象。
字符集
计算机要准确的存储知识识别个人字符集符号,就要进行字符编码,一套字符集必然至少有一套字符编码,常见字符集有ASCII字符集 、GBXXX字符集、Unicode字符集等。 ASCII字符集 是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键,退格,换行键等)可显示字符(英文大小写字符,阿拉伯数字和西文符号)。
基本的ASCII字符集,使用7位表示一个字符,共128字符,ASCII的扩展字符使用8位表示一个字符,共256字符,方便支持欧洲常用字符,是一个系统支持的所有字符的集合。
GBXXX字符集 GBK最常用的中文码表,是在GB2312标准基础上的扩展规范,使用的双字节解码方案。 UTF-8编码 可以用来表示Unicode标准中任意字符,他是电子邮件、网页以及其他存储或传送文字的应用中,优先采用的编码,它使用1至4个字节为每个字符编码。 编码规则: 128个US-ASCII字符,只需要一个字节编码 拉丁文等字符,需要两个字节编码 大部分常用字(含中文),使用三个字节编码 其他极少使用的Unicode辅助字符,使用四字节编码
字符串中的编码解码问题
编码 byte[] getBytes():使用平台的默认字符集将该String编码为一系列字节,将结果存储都新的字节数组中 byte[] getBytes(String charseName):使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中 解码 String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的String String(byte[] bytes,String charseName):通过指定的字符集解码指定的字节数组来构造新的String 使用何种方法编码就要使用何种编码解码
String s="中国";
byte[] bytes=s.getBytes();
System.out.println(Arrays.toString(bytes));
byte[] bytes2=s.getBytes("UTF-8");
System.out.println(Arrays.toString(bytes2));
byte[] bytes3=s.getBytes("GBK");
System.out.println(Arrays.toString(bytes3));
String string=new String(bytes);
System.out.println(string);
String string2=new String(bytes2,"UTF-8");
System.out.println(string);
String string3=new String(bytes,"GBK");
System.out.println(string);
字符流中的编码解码问题
字符流抽象基类: Reader:字符输入流抽象类 Writer:字符输出流抽象类
字符流中和编码解码问题相关的两个类: InputStreamReader:字符输入流 OutputStreamWriter:字符输出流
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\IOTest\\01.txt"));
osw.write("中国");
osw.close();
OutputStreamWriter osw2=new OutputStreamWriter(new FileOutputStream("E:\\IOTest\\01.txt"),"UTF-8");
osw2.write("中国");
osw2.close();
OutputStreamWriter osw3=new OutputStreamWriter(new FileOutputStream("E:\\IOTest\\01.txt"),"GBK");
osw3.write("中国");
osw3.close();
InputStreamReader isr=new InputStreamReader(new FileInputStream("E:\\IOTest\\01.txt"));
int ch;
while( (ch=isr.read())!=-1) {
System.out.println((char)ch);
}
isr.close();
InputStreamReader isr2=new InputStreamReader(new FileInputStream("E:\\IOTest\\01.txt"),"UTF-8");
int ch1;
while ((ch1=isr2.read())!=-1) {
System.out.println(ch1);
}
isr2.close();
InputStreamReader isr3=new InputStreamReader(new FileInputStream("E:\\IOTest\\01.txt"),"GBK");
int ch2;
while((ch2=isr3.read())!=-1) {
System.out.println(ch2);
}
isr3.close();
字符流写数据的五种方式
方法名 | 说明 |
---|
void write(int c) | 写一个字符 | void write(char[] cbuf) | 写一个字符数组 | void write(char[] cbuf,int off,int len) | 写字符数组的一部分 | void write(String str) | 写一个字符串 | void wirte(String str,int off,int len) | 写一个字符串的一部分 |
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\IOTest\\01.txt"));
osw.write(97);
osw.flush();
char[] ch= {'a','b','c','d'};
osw.write(ch);
osw.flush();
osw.write(ch,0,1);
osw.flush();
String string="abcde";
osw.write(string);
osw.flush();
osw.write(string,0,2);
osw.flush();
字符流读数据的两种方式
方法名 | 说明 |
---|
int read() | 一次读一个字符数据 | int read(char[] cbuf) | 一次读一个字符数组数据 |
InputStreamReader isr=new InputStreamReader(new FileInputStream("E:\\IOTest\\01.txt"));
int by;
while((by=isr.read())!=-1) {
System.out.print((char)by);
}
char[] chs=new char[1024];
int len;
while ((len=isr.read(chs))!=-1) {
System.out.println(new String(chs,0,len));
}
isr.close();
案例:复制Java文件
把模块目录下的“Demo.java”复制到模块目录下的“Copy.java”
- FileWriter:用于写入字符文件的便携类
FileWriter(String fileName); - FileReader:用于读取字符文件的便携类
FileReader(String fileName);
若设计编码解码问题,不能使用便携类。
FileWriter osw=new FileWriter("E:\\IOTest\\Demo.java");
FileReader isr=new FileReader("E:\\IOTest\\Copy.java");
int ch;
while((ch=isr.read())!=-1) {
osw.write(ch);
}
char[] chs=new char[1024];
int len;
while((len=isr.read(chs))!=-1) {
osw.write(chs, 0, len);
}
isr.close();
osw.close();
字符缓冲流
BufferedReader:从字符输入流中读取文本 BufferedWriter:将文本写入字符输出流
构造方法 BufferedWriter(Writer out) BufferedReader(Reader in)
BufferedWriter bw=new BufferedWriter(new FileWriter("E:\\IOTest\\01.txt"));
BufferedReader br=new BufferedReader(new FileReader("E:\\IOTest\\02.txt"));
char[] chs=new char[1024];
int len;
while((len=br.read(chs))!=-1) {
bw.write(chs);
}
bw.close();
br.close();
字符缓冲流特有功能
BufferedWriter: void newLine(); 写一行行分隔符,分隔符字符串由系统属性定义
BufferdReader public String readLine(); 读一行文字,结果包含行的内容的字符串,不包括任何终止字符,如果流的结尾已经到达,则为null。
BufferedWriter bw=new BufferedWriter(new FileWriter("E:\\IOTest\\01.txt"));
BufferedReader br=new BufferedReader(new FileReader("E:\\IOTest\\01.txt"));
for (int i = 0; i < 10; i++) {
bw.write("hello");
bw.newLine();
}
bw.flush();
String string;
while ((string=br.readLine())!=null) {
System.out.println(string);
}
案例:字符缓冲流特有功能复制Java文件
BufferedWriter bw=new BufferedWriter(new FileWriter("E:\\IOTest\\01.txt"));
BufferedReader br=new BufferedReader(new FileReader("E:\\IOTest\\02.txt"));
String string;
while ((string=br.readLine())!=null) {
bw.write(string);
bw.newLine();
}
bw.close();
br.close();
IO流小结
|