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

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

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

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

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

1 File

有三个实体:

目录:就是文件夹

文件

路径

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

1.1构造方法

 

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);
	}
}

 

注意:

1)导java.io.File这个包

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

 

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

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

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

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

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);
	}
}

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);
	}
}

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

1.2成员变量

 

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

Tips

 

所以写时不要把路径写死,因为与平台无关,可以把\\换成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);
	}
}

 

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);
	}
}

1.3普通方法

1.3.1获取文件相关信息

 

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);
	}
}

如果是一个相对的路径:

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);
	}
}

还是输出一个绝对的路径

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

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);
	}
}

如果是一个相对的路径:

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);
	}
}

 

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

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);		
	}
}

 

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);		
	}
}

 

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);				
	}
}

就是文件的大小:

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

 

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);				
	}
}

  

如果再执行一遍这个代码,结果就是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);				
	}
}

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

 

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

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);				
	}
}

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

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

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);				
	}
}

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

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

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);					
	}
}

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);					
	}
}

 

 

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);				
	}
}

总结:三个单词:

File 文件

Directory 目录

Path 路径

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

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

1.3.3 listFiles()方法

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

 

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);
		}			
	}
}

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);
		}			
	}
}

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

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

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

 

1.3.4文件过滤器

 

例:

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);
		}
	}
}

 

图说明:

每个文件都传进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);
	}	
}

 

图说明:

 

2100的阶乘 (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));		
	}
}

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

否则会栈内存溢出,

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

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);
			}
		}
	}
}

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);
			}			
		}
	}
}

图说明:

 

3字节流

3.1字节输出流OutputStream

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

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

 

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();
	}
}

练习时可以Throws抛异常:

 

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

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();
	}
}

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();
	}
}

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();
	}
}

Tips:

1)一个字符是两个字节

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

3.1.2给文件中续写和换行

1)续写:

 

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();
	}
}

3.1.3 IO异常的处理

  

处理:

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();
			}
		}		
	}
}

说明:

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

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

3.2字节输入流InputStream

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

 

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

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

 

3.2.1 FileInputStream

 

构造方法:

 

3.2.2读取数据read()方法

 

例:

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();
	}
}

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

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

 

数组长度一般以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();
	}
}

3.2.4复制文件

 

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();
	}
}

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);
	}
}

4字符编码表

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

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

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

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

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

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

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

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

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

Tips:

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

2)能识别中文的码表:GBKUTF-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();
	}
}

 

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

5.1字符输入流Reader

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

 

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

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

5.1.1 FileReader

  

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();
	}
}

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();
	}
}

5.2字符输出流Writer

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

5.2.1FileWriter

构造方法

 

 

5.2.2 flush()close()

 

Tips

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

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

3flush可以无限用

4close最后还能刷一下,所以最后的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();
	}
}

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();
	}
}

不能用字符流复制图片:

 

 

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

总结:

文本文件用字符流

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

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

猜你喜欢

转载自www.cnblogs.com/hzhjxx/p/10205486.html