IO流----File,递归,字节流,字符流

时间:2021-09-07 17:11:31

要把数据持久化存储,就需要把内存中的数据存储到内存以外的其他持久化设备(硬盘、光盘、U盘等)上。

当需要把内存中的数据存储到持久化设备上这个动作称为输出(写)Output操作。

当把持久设备上的数据读取到内存中的这个动作称为输入(读)Input操作。

因此把这种输入和输出动作称为IO操作。

1 File类

有三个实体:

目录:就是文件夹

文件

路径

Java中把文件或者目录(文件夹)都封装成File对象。并且与平台无关。

1.1构造方法

IO流----File,递归,字节流,字符流

1.1.1 File(String pathname)

例:

import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file=new File("E:\\zyx\\javaFile");
System.out.println(file);
}
}

IO流----File,递归,字节流,字符流

注意:

1)导java.io.File这个包

2)路径要转义写成E:\\zyx\\java(两个反斜杠)

IO流----File,递归,字节流,字符流

3)打印file,是默认调用的toString()方法

4)如果文件不存在,也能构造这个对象,构造方法不会判断该路径的文件或目录是否存在

5)如果路径写成:E:\\zyx\\JAVAFile,是一样的,因为windows下不区分大小写

6)windows中,文件名和文件夹名也不能相同

1.1.2 File(String parent, String child)

传一个父路径,一个子路径,这样更灵活,可以当成一个变量传过来

例:

import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file=new File("E:\\zyx","JAVAFile");
System.out.println(file);
}
}

IO流----File,递归,字节流,字符流

1.1.3 File(File parent, String child)

可以传过来一个File对象,那么就能用对象的方法了(前面那两个构造方法只能用字符串的方法)

例:

import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file=new File("E:\\zyx\\JAVAFile");
File file2=new File(file,"a.txt");
System.out.println(file2);
}
}

IO流----File,递归,字节流,字符流

三个构造方法,根据具体需求来用,一般用第一个直接传路径的。

1.2成员变量

IO流----File,递归,字节流,字符流

这其实是两个变量,一样的用法,只是返回值不同,平时只用String的就可以。

Tips:

IO流----File,递归,字节流,字符流

所以写时不要把路径写死,因为与平台无关,可以把\\换成File.separator

例:

import java.io.File;
public class FileTest {
public static void main(String[] args) {
//与系统有关的路径分隔符
String s1=File.pathSeparator;
System.out.println(s1); //结果是分号
//与系统有关的名称分隔符
String s2=File.separator;
System.out.println(s2);
}
}

IO流----File,递归,字节流,字符流

import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file=new File("E:"+File.separator+"zyx"+File.separator+"JAVAFile");
System.out.println(file);
}
}

IO流----File,递归,字节流,字符流

1.3普通方法

1.3.1获取文件相关信息

IO流----File,递归,字节流,字符流

1)返回文件的绝对路径:

import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file=new File("E:\\zyx\\JAVAFile");
String path=file.getAbsolutePath();
System.out.println(path);
}
}

IO流----File,递归,字节流,字符流

如果是一个相对的路径:

import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file=new File("abc");
String path=file.getAbsolutePath();
System.out.println(path);
}
}

IO流----File,递归,字节流,字符流

还是输出一个绝对的路径

注意:相对路径中用/分隔。绝对路径用\\

2)获取文件名和路径

import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file=new File("E:\\zyx\\JAVAFile");
String name=file.getName(); //获取文件名或文件夹名
String path=file.getPath(); //获取绝对路径
System.out.println("name:"+name);
System.out.println("path:"+path);
}
}

IO流----File,递归,字节流,字符流

如果是一个相对的路径:

import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file=new File("demo02");
String name=file.getName(); //获取文件名或文件夹名
String path=file.getPath(); //获取绝对路径
System.out.println("name:"+name);
System.out.println("path:"+path);
}
}

IO流----File,递归,字节流,字符流

这个方法只是把路径以字符串的形式输出一下

3)isAbsolute()测试抽象路径名是否为绝对路径名

import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file=new File("E:\\zyx\\javaFile");
boolean flag=file.isAbsolute();
System.out.println(flag);
}
}

IO流----File,递归,字节流,字符流

import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file=new File("abc");
boolean flag=file.isAbsolute();
System.out.println(flag);
}
}

IO流----File,递归,字节流,字符流

4)length()

import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file=new File("E:\\zyx\\javaFile\\eclipse.zip");
long size=file.length();
System.out.println(size);
}
}

IO流----File,递归,字节流,字符流

就是文件的大小:

IO流----File,递归,字节流,字符流

1.3.2文件和文件夹的创建、删除

IO流----File,递归,字节流,字符流

1)创建文件

import java.io.File;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) throws IOException {
File file=new File("E:\\zyx\\javaFile\\a.txt");
boolean flag=file.createNewFile();
System.out.println(flag);
}
}

IO流----File,递归,字节流,字符流  

IO流----File,递归,字节流,字符流

如果再执行一遍这个代码,结果就是false了。

如果这样写:

import java.io.File;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) throws IOException {
File file=new File("E:\\zyx\\javaFile\\a");
boolean flag=file.createNewFile();
System.out.println(flag);
}
}

IO流----File,递归,字节流,字符流

可以看到创建了一个名字为a的文件,其文件类型是“文件”

IO流----File,递归,字节流,字符流

所以这个方法只能创建文件,不能创建文件夹

2)删除文件或目录

import java.io.File;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) throws IOException {
File file=new File("E:\\zyx\\javaFile\\a");
boolean flag=file.delete();
System.out.println(flag);
}
}

IO流----File,递归,字节流,字符流

删除的文件或目录不进回收站,直接从硬盘上删除,所以要谨慎调用这个方法。

3)exists() 判断是否存在文件或文件夹

import java.io.File;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) throws IOException {
File file=new File("E:\\zyx\\java");
boolean flag=file.exists();
System.out.println(flag);
}
}

IO流----File,递归,字节流,字符流

所以进行文件操作时,要先判定一下是否存在

4)isDirectory() 判断文件对象是否是文件夹(目录)

import java.io.File;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) throws IOException {
File file=new File("E:\\zyx\\java\\a");
boolean flag=file.isDirectory();
System.out.println(flag);
}
}

IO流----File,递归,字节流,字符流

5)创建目录

mkdir()只能创建一个(一级)目录

例:

import java.io.File;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) throws IOException {
File file=new File("E:\\zyx\\java\\b");
boolean flag=file.mkdir();
System.out.println(flag);
}
}

IO流----File,递归,字节流,字符流

IO流----File,递归,字节流,字符流

mkdirs()可以创建多级目录,一级也能创建,所以一般用这个

例:

import java.io.File;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) throws IOException {
File file=new File("E:\\zyx\\java\\f\\a\\b\\c");
boolean flag=file.mkdirs();
System.out.println(flag);
}
}

IO流----File,递归,字节流,字符流

IO流----File,递归,字节流,字符流

总结:三个单词:

File 文件

Directory 目录

Path 路径

先判断是否存在,再判断是不是目录,不是,那就一定是文件

因为系统上只有文件或文件夹

1.3.3 listFiles()方法

获取一个目录中的所有文件或者目录中的文件夹:

IO流----File,递归,字节流,字符流

例1:

import java.io.File;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) throws IOException {
File file=new File("E:\\zyx\\java");
String[] files=file.list();
for(String s:files){
System.out.println(s);
}
}
}

IO流----File,递归,字节流,字符流

例2:

import java.io.File;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) throws IOException {
File file=new File("E:\\zyx\\java");
File[] files=file.listFiles();
for(File f:files){
System.out.println(f);
}
}
}

IO流----File,递归,字节流,字符流

注意:在获取指定目录下的文件或者文件夹时必须满足下面两个条件

1)指定的目录必须是存在的,

2)指定的必须是目录。否则容易引发返回数组为null,出现NullPointerException

IO流----File,递归,字节流,字符流

1.3.4文件过滤器

IO流----File,递归,字节流,字符流

IO流----File,递归,字节流,字符流

例:

import java.io.File;
import java.io.FileFilter; public class MyFileter implements FileFilter{
public boolean accept(File pathname) {
return pathname.getName().toLowerCase().endsWith(".java"); //转小写,以.java结尾
}
}
import java.io.File;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) throws IOException {
File file=new File("E:\\zyx\\java");
File[] files=file.listFiles(new MyFileter());
for(File f:files){
System.out.println(f);
}
}
}

IO流----File,递归,字节流,字符流

图说明:

IO流----File,递归,字节流,字符流

每个文件都传进accept方法中,符合的,放入files数组中

是listFiles调用的accept方法

2递归

2.1递归概述

指在当前方法内调用自己的这种现象

例1:

public class Demo04 {
public static void main(String[] args) {
System.out.println(getSum(3));
}
//递归
public static int getSum(int n){
if(n==1){
return 1;
}
return n+getSum(n-1);
}
}

IO流----File,递归,字节流,字符流

图说明:

IO流----File,递归,字节流,字符流

例2:100的阶乘 (100!也就是100*99*98*...1)

import java.math.BigInteger;
public class Test {
public static void main(String[] args) {
System.out.println(getSum(100));
}
//递归求阶乘
public static BigInteger getSum(Integer n){
BigInteger big=new BigInteger(n.toString());
if(n==1){
return new BigInteger("1");
}
return big.multiply(getSum(n-1));
}
}

IO流----File,递归,字节流,字符流

自己调用自己,但是要给出口,

否则会栈内存溢出,

递归次数不要太多,还是会溢出,

IO流----File,递归,字节流,字符流

IO流----File,递归,字节流,字符流

2.2递归打印所有子目录中的文件路径

import java.io.File;
public class FileTest {
public static void main(String[] args) {
File file = new File("E:\\zyx\\java");
getFileAll(file);
} // 获取指定目录以及子目录中的所有的文件
public static void getFileAll(File file) {
File[] files = file.listFiles();
// 遍历当前目录下的所有文件和文件夹
for (File f : files) {
// 判断当前遍历到的是否为目录
if (f.isDirectory()) {
// 是目录,继续获取这个目录下的所有文件和文件夹
getFileAll(f);
} else {
// 不是目录,说明当前f就是文件,那么就打印出来
System.out.println(f);
}
}
}
}

IO流----File,递归,字节流,字符流

2.3递归过滤文件(包括子目录)

import java.io.File;
import java.io.FileFilter; public class MyFileter implements FileFilter{
public boolean accept(File pathname) {
if(pathname.isDirectory()){
return true;
}
return pathname.getName().toLowerCase().endsWith(".java");
}
}
import java.io.File;

public class Demo05 {
public static void main(String[] args) {
File file=new File("E:\\zyx\\java");
getFile(file);
} //递归加过滤
public static void getFile(File dir){
File[] files=dir.listFiles(new MyFileter());
for(File f:files){
//如果是文件夹,则调用自己
if(f.isDirectory()){
getFile(f);
}else{
System.out.println(f);
}
}
}
}

IO流----File,递归,字节流,字符流

图说明:

IO流----File,递归,字节流,字符流

3字节流

3.1字节输出流OutputStream

OutputStream此抽象类,是表示输出字节流的所有类的超类。操作的数据都是字节,定义了输出字节流的基本共性功能方法。

输出流中定义都是写write方法:

IO流----File,递归,字节流,字符流

3.1.1 FileOutputStream类

OutputStream有很多子类,其中子类FileOutputStream可用来写入数据到文件。

构造方法:

例:

import java.io.FileOutputStream;
import java.io.IOException; public class MyTest {
public static void main(String[] args) throws IOException {
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream("E:\\zyx\\java\\demo.txt");
// 写字节
fos.write(100);
fos.write(49);
fos.write(48);
fos.write(48);
// 释放资源
fos.close();
}
}

IO流----File,递归,字节流,字符流

练习时可以Throws抛异常:

IO流----File,递归,字节流,字符流

IO流----File,递归,字节流,字符流

创建的文件对象,如果文件不存在,会创建一个,如果有,则覆盖

write写时,底层会转换成二进制,写进也是二进制,但是是txt文本文件,所以走ascii表,解析成可以看懂的。

写字节数组:

import java.io.FileOutputStream;
import java.io.IOException; public class MyTest {
public static void main(String[] args) throws IOException {
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream("E:\\zyx\\java\\demo.txt");
// 写字节数组
byte[] bytes = { 97, 98, 99, 100 };
fos.write(bytes);
// 释放资源
fos.close();
}
}

IO流----File,递归,字节流,字符流

import java.io.FileOutputStream;
import java.io.IOException; public class MyTest {
public static void main(String[] args) throws IOException {
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream("E:\\zyx\\java\\demo.txt");
// 写字节数组
byte[] bytes = { 97, 98, 99, 100 };
fos.write(bytes,1,1);
//fos.write("字符串转成字节数组".getBytes());
// 释放资源
fos.close();
}
}

IO流----File,递归,字节流,字符流

import java.io.FileOutputStream;
import java.io.IOException; public class MyTest {
public static void main(String[] args) throws IOException {
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream("E:\\zyx\\java\\demo.txt");
// 写字节数组
fos.write("字符串转成字节数组".getBytes());
// 释放资源
fos.close();
}
}

IO流----File,递归,字节流,字符流

Tips:

1)一个字符是两个字节

2)文本文件:用txt打开可以看懂,就是文本文件。看不懂的就是字节文件。

3.1.2给文件中续写和换行

1)续写:

IO流----File,递归,字节流,字符流

2)\r\n换行

例:

import java.io.FileOutputStream;
import java.io.IOException; public class MyTest {
public static void main(String[] args) throws IOException {
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream("E:\\zyx\\java\\demo.txt", true);
// 写字节数组
byte[] bytes = { 97, 98, 99, 100 };
fos.write(bytes);
fos.write(bytes, 1, 1);
fos.write("hello,java".getBytes());
// 换行
fos.write("\r\nhello,java".getBytes());
// 释放资源
fos.close();
}
}

IO流----File,递归,字节流,字符流

3.1.3 IO异常的处理

IO流----File,递归,字节流,字符流

处理:

import java.io.FileOutputStream;
import java.io.IOException; public class Demo02 {
public static void main(String[] args) {
//创建字节输出流对象
FileOutputStream fos=null;
try {
//创建字节输出流对象
fos=new FileOutputStream("E:\\zyx\\java\\test.txt");
fos.write("你好".getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
//如果发生异常,中止程序
throw new RuntimeException();
}finally{
//释放资源
try {
if(fos!=null)
fos.close(); //如果创建时就发生异常,则没必要关了
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException();
}
}
}
}

说明:

1)FileNotFoundException异常是IOException异常的子类,所以抛一个IO异常就可以

2)throw new RuntimeException();这句:如果下面还有写入操作,那么上面发生异常,则不能再走了,就加一个程序终止

3.2字节输入流InputStream

InputStream此抽象类,是表示字节输入流的所有类的超类。定义了字节输入流的基本共性功能方法。

IO流----File,递归,字节流,字符流

int read():读取一个字节并返回,没有字节返回-1.

int read(byte[]): 读取一定量的字节数,并存储到字节数组中,返回读取到的字节数。

3.2.1 FileInputStream类

IO流----File,递归,字节流,字符流

构造方法:

IO流----File,递归,字节流,字符流

3.2.2读取数据read()方法

IO流----File,递归,字节流,字符流

例:

import java.io.FileInputStream;
import java.io.IOException; public class MyTest2 {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("E:\\zyx\\java\\demo.txt");
int len=0;
while((len=fis.read())!=-1){
System.out.print((char)len);
}
fis.close();
}
}

IO流----File,递归,字节流,字符流

Tips:read()循环,要用一个变量len来做判断,不然还会往后读,和之前学的next()类似。

3.2.3读取数据read(byte[])方法

IO流----File,递归,字节流,字符流

数组长度一般以1024为单位

例:

import java.io.FileInputStream;
import java.io.IOException; public class MyTest2 {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("E:\\zyx\\java\\demo.txt");
//创建数组
byte[] bytes=new byte[2];
int len=0;
while((len=fis.read(bytes))!=-1){
System.out.print(new String(bytes,0,len)); //有效字符长度
}
fis.close();
}
}

IO流----File,递归,字节流,字符流

3.2.4复制文件

IO流----File,递归,字节流,字符流

例1:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; public class MyTest {
public static void main(String[] args) throws IOException {
// 明确数据源
FileInputStream fis = new FileInputStream("E:\\zyx\\java\\demo.txt");
// 明确目的地
FileOutputStream fos = new FileOutputStream("E:\\zyx\\java\\demoCopy.txt");
// 开始复制
int len = 0;
while ((len = fis.read()) != -1) {
fos.write(len);
}
fis.close();
fos.close();
}
}

IO流----File,递归,字节流,字符流

例2:复制压缩包(或图片),并记录复制的时间

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; public class Test {
public static void main(String[] args) throws IOException {
method01();
}
//复制
public static void method01() throws IOException{
//明确数据源
FileInputStream fis=new FileInputStream("E:\\zyx\\java\\eclipse.zip");
//明确目的地
FileOutputStream fos=new FileOutputStream("E:\\zyx\\java\\a\\eclipse.zip");
//开始复制
byte[] bytes=new byte[1024];
long start=System.currentTimeMillis();
int len=0;
while((len=fis.read(bytes))!=-1){
fos.write(bytes);
}
fis.close();
fos.close();
long end=System.currentTimeMillis();
System.out.println(end-start);
}
}

IO流----File,递归,字节流,字符流

4字符编码表

就是生活中字符和计算机二进制的对应关系表。

1、ascii: 一个字节中的7位就可以表示。对应的字节都是正数。0-xxxxxxx

2、iso-8859-1:拉丁码表 latin,用了一个字节用的8位。1-xxxxxxx  负数。

3、GB2312:简体中文码表。包含6000-7000中文和符号。用两个字节表示。两个字节第一个字节是负数,第二个字节可能是正数

4、GBK:目前最常用的中文码表,2万的中文和符号。用两个字节表示,其中的一部分文字,第一个字节开头是1,第二字节开头是0

5、GB18030:最新的中文码表,目前还没有正式使用。

6、unicode:国际标准码表,无论是什么文字,都用两个字节存储。

Java中的char类型用的就是这个码表。char c = 'a'; 占两个字节。

7、UTF-8:基于unicode,一个字节就可以存储数据,不用两个字节存储,而且这个码表更加的标准化,在每一个字节头加入了编码信息(后期到api中查找)。

Tips:

1)Java中的字符串是按照系统默认码表来解析的,简体中文版字符串默认的码表是GBK。

2)能识别中文的码表:GBK、UTF-8;正因为识别中文码表不唯一,涉及到了编码解码问题。

3)对于开发人员,常见的编码:GBK  UTF-8  ISO-8859-1(以后jsp用)

4)文字--->(数字) :编码。 “abc”.getBytes()  byte[]

(数字)--->文字:解码。 byte[] b={97,98,99}  new String(b,0,len)

5字符流

例:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; public class MyTest {
public static void main(String[] args) throws IOException {
// 给文件中写中文
writeCNText();
// 读取文件中的中文
readCNText();
} // 写中文
public static void writeCNText() throws IOException {
FileOutputStream fos = new FileOutputStream("E:\\zyx\\java\\test.txt");
fos.write("欢迎你".getBytes());
fos.close();
} // 读取中文
public static void readCNText() throws IOException {
FileInputStream fis = new FileInputStream("E:\\zyx\\java\\test.txt");
int ch = 0;
while ((ch = fis.read()) != -1) {
System.out.println(ch);
}
fis.close();
}
}

IO流----File,递归,字节流,字符流

用字节流读取的全是字节,所以要用到字符流来进行文本文件的读和写。

5.1字符输入流Reader

Reader,读取字符流的抽象超类

IO流----File,递归,字节流,字符流

read():读取单个字符并返回

read(char[]):将数据读取到数组中,并返回读取的个数。

5.1.1 FileReader类

IO流----File,递归,字节流,字符流

例1:

import java.io.FileReader;
import java.io.IOException; public class MyTest {
public static void main(String[] args) throws IOException {
// 创建字符输入流
FileReader fr = new FileReader("E:\\zyx\\java\\demo.txt");
int len = 0;
while ((len = fr.read()) != -1) {
System.out.print((char) len);
}
fr.close();
}
}

IO流----File,递归,字节流,字符流

例2:

import java.io.FileReader;
import java.io.IOException; public class MyTest {
public static void main(String[] args) throws IOException {
FileReader fr=new FileReader("E:\\zyx\\java\\demo.txt");
char[] ch=new char[2]; //缓冲容器的作用
int len=0;
while((len=fr.read(ch))!=-1){
System.out.print(new String(ch,0,len));
}
fr.close();
}
}

IO流----File,递归,字节流,字符流

5.2字符输出流Writer

Writer是写入字符流的抽象类。

IO流----File,递归,字节流,字符流

5.2.1FileWriter类

构造方法

IO流----File,递归,字节流,字符流

5.2.2 flush()和close()

IO流----File,递归,字节流,字符流

Tips:

1)close有可能发生异常,不执行,所以写一次Flush刷一次

2)close只能用一次,关了后,对象就不能用了

3)flush可以无限用

4)close最后还能刷一下,所以最后的flush可以不用写

例:

import java.io.FileWriter;
import java.io.IOException; public class MyTest2 {
public static void main(String[] args) throws IOException {
FileWriter fw=new FileWriter("E:\\zyx\\java\\demo.txt",true); //有true是续写
fw.write(100); //走ascii
fw.flush(); char[] ch={'a','中','b'};
fw.write(ch);
fw.flush(); fw.write("你好");
fw.flush(); fw.close();
}
}

IO流----File,递归,字节流,字符流

5.2.3复制文本文件

例:

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException; public class MyTest2 {
public static void main(String[] args) throws IOException {
// 明确数据源
FileReader fr = new FileReader("E:\\zyx\\java\\demo.txt");
// 明确目的地
FileWriter fw = new FileWriter("E:\\zyx\\java\\a\\demo.txt");
int len = 0;
char[] ch = new char[1024];
while ((len = fr.read(ch)) != -1) {
fw.write(ch, 0, len);
fw.flush();
}
fr.close();
fw.close();
}
}

IO流----File,递归,字节流,字符流

不能用字符流复制图片:

IO流----File,递归,字节流,字符流

IO流----File,递归,字节流,字符流

IO流----File,递归,字节流,字符流

IO流----File,递归,字节流,字符流

可以看到,虽然复制了,但是图片无法查看。

总结:

文本文件用字符流

图片,视频,压缩包等用字节流

用到的字节数组或字符数组一般以1024为单位