Java程序设计——IO流

目录

一、概念

二、字节流

1.InputStream的方法:

方法

功能

2.InputStream的子类:

3.OutputStream的方法:

4.OutputStream的子类:

5.字节流读写文件:

6.文件拷贝

7.字节缓冲流

三、字符流

1.字符流读写文件

2.字符缓冲流

3.跟踪行号的输入流

4.转换流

四、其它IO流

1.ObjectOutputStream和ObjectInputStream(对象流)

2.DataInputStream和DatOutputStream(数据流)

3.PrintStream(输出流)

4.标准输入输出流

5.PipedInputStream和PipedOutputStream(管道流)

6.ByteArrayInputStream和ByteArrayOutputStream(字节数组流)

7.CharArrayReader和CharArrayWriter(字符数组流)

8.SequenceInputStream(序列流)

五、File类

1.File类的常用方法:

1.1.创建目录、文件

1.2.常用方法的实现

​编辑

2.遍历目录下的文件

2.删除文件及目录

六、RandomAccesseFile

七、字符编码

1.字符编码和解码

2.字符传输


一、概念

大多数应用程序都需要实现与设备之间的数据传输,例如,键盘可以输入数据,显示器可以显示程序的运行结果等

在Java中,将这种通过不同输入/输出设备(键盘,内存,显示器,网络等)之间的数据传输抽象表述为“流”,程序允许通过流的方式与输入/输出设备进行数据传输

Java中的“流”都位于java.io包中,称为IO(输入/输出)

IO流有很多种,按照操作数据的不同,可以分为字节流字符流,按照数据传输方向的不同又可分为输入流输出流,程序从输入流中读取数据,向输出流中写入数据。

二、字节流

在计算机中,无论是文本、图片、音频还是视频,所有的文件都是以二进制(字节)形式存在,IO流中针对字节的输入输出提供了一系列的流,统称为字节流。

JDK中,提供了两个抽象类InputStreamOutputStream,它们是字节流的顶级父类,所有的字节输入流继承自InputStream,所有的字节输出流都继承自OutputStream

1.InputStream的方法:

方法

功能

 public int read()                                                           

read()从输入流中读取数据的下一个字节,返回0~255范围的int类型的整数,如果到达流末尾,则返回-1.

无参数的read()返回的数据为实际读取到的字节值的整数

 public int read(byte[]   b)       

                       

有参数的read()则是将数据读取到字节数组中,返回的是实际读取到的字节个数。
public int read(byte[] b,  int off , int len) 从输入流中读取若干字节,将其保存在以off为起始下标的字节数组中,一共保存len个字节数据
public int mark(int readlimit)在输入流的当前位置放置一个标记,readlimit参数告知此输入流在标记位置失效之前允许读取的字节数
public int reset()将输入指针返回当前所做的标记处
public int skip(long n)跳过输入流的n个字节并返回实际跳过的字节数
public boolean markSupported()如果当前流支持mark()/reset()操作就返回true
public void close()关闭输入流并释放与此流相关的系统资源

2.InputStream的子类:

3.OutputStream的方法:

方法

功能

public void write(int value)将字节写到输出流
public void write(byte[ ]  array)将指定的byte字节数组里的全部字节写到输出流
public void write(byte[] array, int off, int len)将指定byte数组以off为下标开始的len个字节写到输出流
public void close()关闭输出流并释放与该流相关的所有系统资源
public void flush()刷新输出流并清空缓存区

4.OutputStream的子类:

5.字节流读写文件:

  • FileInputStream:它是操作文件的字节输入流,专门用于读取文件的数据
import java.io.FileInputStream;
import java.io.IOException;

public class Test_FileInputStream {

	public static void main(String[] args) throws IOException {
		// 创建一个文件输入字节流
		FileInputStream fin = new FileInputStream("D:\\JAVA Program\\fileinputstream.txt");
		int b = 0; // 定义int类型的变量记住每次读取的字节
		while(true) {
			b = fin.read();	// 变量b记住读取的每一个字节de整型数据
			if(b==-1)	
				break;
			
			System.out.println(b); // 将读取到的b输出
		}
		
		fin.close(); // 关闭文件输入字节流和有关的系统资源
	}

}

  • FileOutputStream:它是操作数据的字节输出流,专门将数据写入到文件中

import java.io.FileOutputStream;
import java.io.IOException;

public class Test_FileOutputStream {

	public static void main(String[] args) throws IOException {
		// 创建一个文件输出字节流
		FileOutputStream fos = new FileOutputStream("D:\\JAVA Program\\fileinputstream.txt");
		String str = "数据写入成功!";
		byte[] b = str.getBytes();	// 将字符串类型数据转化为字节型数据保存在字节数组中
		for(int i = 0; i<b.length; ++i) {
			fos.write(b[i]);
		}
		
		fos.close();
	}

}

 通过运行结果可以得知,如果是通过FileOutputStream向一个已存在的文件写入数据,那么此文件原有的数据将会被清空,从而写入新的数据。

若希望在输入新的数据时,原有数据还能继续保存,则可以使用FileOutputStream的构造函数来实现,代码如下:

FileOutputStream (String fileName,boolean append)

import java.io.FileOutputStream;
import java.io.IOException;

public class Test_FileOutputStream {

	public static void main(String[] args) throws IOException {
		// 创建一个文件输出字节流
		FileOutputStream fos = new FileOutputStream("D:\\JAVA Program\\fileinputstream.txt", true);
		String str = "\n原有数据保留......";
		byte[] b = str.getBytes();	// 将字符串类型数据转化为字节型数据保存在字节数组中
		for(int i = 0; i<b.length; ++i) {
			fos.write(b[i]);
		}
		
		fos.close();
	}

}

6.文件拷贝

文件拷贝:通过输入流读取文件中的数据,通过输出流将文件中的数据写入到另一个文件

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test_FileCopy {

	public static void main(String[] args) throws IOException {
		// 创建文件输入、输出字节流(读取C盘下的mp3文件写入到D盘文件夹中)
		FileInputStream is = new FileInputStream("C:\\林俊杰-裹着心的光.mp3");
		FileOutputStream os = new FileOutputStream("D:\\JAVA Program\\林俊杰-裹着心的光.mp3");
		
		byte[] buff = new byte[1024]; // 定义字节数组作为缓冲区
		int len; 	// 定义整型变量来记住读入缓冲区的字节数
		while((len = is.read(buff)) != -1) {   // 当len为-1,说明到了文件末尾,循环结束
			os.write(buff,0,len); // 从第一个字节开始,向文件写入len个字节
			
		}
		
		is.close();
		os.close();
		
	}

}

7.字节缓冲流

IO包中提供两个带缓冲的字节流,分别是BufferedInputStreamBufferdOutputStream,这两个流都使用了装饰设计模式。它们的构造方法中分别接收InputStreamOutputStream类型的参数作为被包装对象,在读写数据时提供缓冲功能。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test_BufferedStream {
	public static void main(String args[]) throws IOException {
		// 创建一个带缓冲区的输入、输出流
		FileInputStream fis = new FileInputStream("D:\\JAVA Program\\fileinputstream.txt");
		FileOutputStream fos = new FileOutputStream("D:\\JAVA Program\\test.txt");
		BufferedInputStream bis = new BufferedInputStream(fis);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		
		int len;
		while((len = bis.read()) != -1) {
			bos.write(len);
		}
		
		bis.close();
		bos.close();
		
	}
}

 BufferedInputStreamBufferedOutputStream两个缓冲流对象,这两个流内部都定义了一个大小为8192的字节数组,当调用read()或者write()方法读写数据时,首先将读写的数据存入定义好的字节数组,然后将字节数组的数据一次性读写到文件中,有效的提高数据的读写效率。

三、字符流

  • Reader是字符输入流,用于从某个源设备读取字符

  • Writer是字符输出流,用于向某个目标设备写入字符

1.字符流读写文件

  • FileReader:可以从关联文件中读取一个或一组字符
import java.io.FileReader;
import java.io.IOException;

public class Test_FileReader {

	public static void main(String[] args) throws IOException {
		//	定义一个文件字符输入流
		FileReader fr = new FileReader("D:\\JAVA Program\\FileReader.txt");
		
		int ch; // 用于记录读取出来的字符
		while((ch = fr.read()) != -1){ // ch为-1,表示已到文件末尾,退出循环
			System.out.println((char)ch);
		}
		
		fr.close();
		
	}

}

 

  • FileWriter:可以向文件中写入字符
import java.io.FileWriter;
import java.io.IOException;

public class Test_FileWriter {

	public static void main(String[] args) throws IOException {
		// 创建一个文件字符输出流对象
		FileWriter fw = new FileWriter("D:\\JAVA Program\\FileWrider.txt");
		String str = "You completed me";
		fw.write(str);	//	将字符串写入到文件中
		fw.close();
	}

}

2.字符缓冲流

 字符流提供了带缓冲区的包装流,分别是BufferedReaderBufferedWriter,其中BufferedReader用于对字符输入流进行包装,BufferedWriter用于对字符输出流进行包装

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Test_Buffered {

	public static void main(String[] args) throws IOException {
		FileReader fr = new FileReader("D:\\JAVA Program\\BufferedReader.txt");
		FileWriter fw = new FileWriter("D:\\JAVA Program\\BufferedRWader.txt");
		
		BufferedReader br = new BufferedReader(fr);
		BufferedWriter bw = new BufferedWriter(fw);
		
		String str;  // 用于记录从缓冲区读出来的文本
		while((str = br.readLine()) != null) {	// 每次读取一行文本,判断是否到文件末尾
			bw.write(str);
			bw.newLine(); // 写入一个换行符
			
		}
		
		br.close();
		bw.close();
		
		
	}

}

在拷贝过程中,每次循环都使用readLine()方法读取文件的一行,然后通过write()方法写入目标文件。其中readLine()方法会逐个读取字符,当读到回车"\r" 或 换行"\n" 时会将读到的字符作为一行的内容返回。

3.跟踪行号的输入流

跟踪行号的输入流——LineNumberReader它是BufferedReader的直接子类

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;

public class Test_LineNumberReader {

	public static void main(String[] args) throws IOException {
		// 创建文件字符输入、输出流对象
		FileReader fr = new FileReader("D:\\JAVA Program\\FileReader.txt");
		FileWriter fw= new FileWriter("D:\\JAVA Program\\lineReader.txt");
		
		LineNumberReader lb = new LineNumberReader(fr); // 包装
		lb.setLineNumber(0); //	设置读取文件的起始行号
		
		String line = null;
		while((line = lb.readLine()) != null) {
			fw.write(lb.getLineNumber()+ ":" + line); // 将行号写入到文件夹
			fw.write("\r\n");
		}
		
		fw.close();
		lb.close();
	}

}

在拷贝过程中,使用LineNumberReader类跟踪行号,首先调用setLineNumber()方法设置行号的初始值,本例中将行号起始值置为0。从运行结果可以看出,调用getLineNumber()方法读取行号时,行号是从1开始的。这是因为LineNumberReader类在读取到换行符('\n')、回车符('\r')或者回车后紧跟换行符时,会将行号自动加1

4.转换流

转换流是一种包装流。

OutputStreamWriterWriter的子类,可以将一个字符输出流包装成字节输出流,方便直接写入字符,

InputStreamReaderReader的子类,它可以将一个字节输入流包装成字符输入流,方便直接读取字符。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Test_StreamReaderWriter {

	public static void main(String[] args) throws IOException {
		// 创建字节输入、输出流对象
		FileInputStream fis = new FileInputStream("D:\\JAVA Program\\fileinputstream.txt");
		FileOutputStream fos = new FileOutputStream("D:\\JAVA Program\\fileoutputstream.txt");
		
		// 将字节输入、输出流转换成字符输入、输出流
		InputStreamReader ir = new InputStreamReader(fis);
		OutputStreamWriter ow = new OutputStreamWriter(fos);
		
		// 对字符输入、输出流进行包装
		BufferedReader br = new BufferedReader(ir);
		BufferedWriter bw = new BufferedWriter(ow);
	
		String str;
		while((str = br.readLine()) != null) {
			bw.write(str);
		}
		
		br.close();
		bw.close();
	
	
	}

}

四、其它IO流

1.ObjectOutputStream和ObjectInputStream(对象流)

ObjectOutputStream(对象输出流)永久将对象转为字节数据写入到硬盘上,即对象序列化

  • 当对象进行序列化时,必须保证该对象实现Serializable接口,否则程序会出现NotSerializableException异常

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Test_ObjectOutputStream {

	public static void main(String[] args) throws IOException {
		Student s = new Student("zhangsan",60);
		System.out.println("——————写入文件前——————");
		System.out.println("name = " + s.getname());
		System.out.println("age = " + s.getage());
		
		// 创建文件输出流对象,将数据写入文件中
		FileOutputStream fos = new FileOutputStream("D:\\JAVA Program\\objectoutputstream.txt");
		
		// 创建对象输出流对象,用于处理文件输出流对象写入的数据
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		
		// 将Student对象写入到输出流中
		oos.writeObject(s);
				
	}

}

class Student implements Serializable{  // 切记要实现Serializable接口
	private String name;
	private int age;
	
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public String getname(){
		return name;
	}
	
	public int getage(){
		return age;
	}
}

Student对象被序列化后会生成二进制数据保存在文件中,通过这些二进制数据可以恢复序列化之前的Java对象,此过程称为反序列化JDK提供了ObjectInputStream类(对象输入流可以实现对象的反序列化

ObjectInputStream(对象输入流):把二进制数据恢复序列化之前的Java对象即反序列

package 对象输出流;


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Test_ObjectInputStream {

	public static void main(String[] args) throws IOException, ClassNotFoundException {
		
		// 创建文件输入流对象,用于读取数据
		FileInputStream fis = new FileInputStream("D:\\JAVA Program\\objectoutputstream.txt");
		
		// 创建对象输入流对象,用于从指定的输入流中读取数据
		ObjectInputStream ois = new ObjectInputStream(fis);
		
		// 从文件中读取数据
		Student s = (Student)ois.readObject();
		System.out.println("——————从文件读取后——————");
		System.out.println("name = " + s.getname());
		System.out.println("age = " + s.getage());
				
	}

}

class Student {  
	private String name;
	private int age;
	
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public String getname(){
		return name;
	}
	
	public int getage(){
		return age;
	}
}

2.DataInputStream和DatOutputStream(数据流)

DataInputStreamDateOutputStream是两个与平台无关的数据操作流

它们不仅提供读写各种基本类型数据的方法,而且还提供了readUTF()writeUTF()方法

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test_DataStream {

	public static void main(String[] args) throws IOException {
		
	//	向文件中写入数据	
		FileOutputStream fos = new FileOutputStream("D:\\JAVA Program\\BufferedRWader.txt");
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		DataOutputStream dos = new DataOutputStream(bos);
		dos.writeChar('5');
		dos.writeUTF("Hello World");
		dos.writeBoolean(false);
		dos.close();
		
	
	//	从文件中读出数据
		FileInputStream fis = new FileInputStream("D:\\JAVA Program\\BufferedRWader.txt");
		BufferedInputStream bis = new BufferedInputStream(fis);
		DataInputStream dis = new DataInputStream(bis);
		System.out.println(dis.readChar());
		System.out.println(dis.readUTF());
		System.out.println(dis.readBoolean());
		dis.close();
	
	}

}

通过DataOutputStream的writeChar()、writeUTF()和writeBoolean()方法依次写入Char、UTF和Boolean格式的数据,然后通过DataInputStreamreadChar()readUTF()和readBoolean()方法将对应类型的数据依次读取,需要注意的是只有读取数据的顺序与写数据的顺序保持一致,才能保证最终数据的正确性.

3.PrintStream(输出流)

PrintStream被称作打印流,它提供了一系列用于打印数据的print()println()方法,可以将基本数据类型的数据或引用数据类型的对象格式化成字符串后再输出

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

public class Test_PrintStream {

	public static void main(String[] args) throws FileNotFoundException {
		FileOutputStream fos = new FileOutputStream("D:\\JAVA Program\\BufferedReader.txt");
		PrintStream ps = new PrintStream(fos);
		ps.print("年龄:");
		ps.println("18");
		ps.print("性别:");
		ps.println("男");
		
	}

}

PrintStreamprint()println()方法区别在于println()方法在输出数据的同时还输出了换行符。

4.标准输入输出流

  • 在System类中定义了三个常量:inouterr,它们被习惯性地称为标准输入输出流
  • in为InputStream类型,它是标准输入流,默认情况下用于读取键盘输入的数据
  • out为PrintStream类型,它是标准输出流,默认将数据输出到命令行窗口
  • err也是PrintStream类型,它是标准错误流,它和out一样也是将数据输出到控制台,它输出的是应用程序运行时的错误信息

5.PipedInputStream和PipedOutputStream(管道流)

PipedInputStreamPipedOutputStream称作管道流,它是一种比较特殊的流,必须先建立连接才能进行彼此间通信

PipedOutputStream用于向管道中写入数据

PipedInputStream用于从管道中读取写入的数据


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;

public class Test_PipedStream {

	public static void main(String[] args) throws IOException {
		// 创建管道流对象
		PipedInputStream pis = new PipedInputStream();
		PipedOutputStream pos = new PipedOutputStream();

		//	管道之间建立通道
		pis.connect(pos);
		
		//	创建一个线程用来发送数据
		new Thread(new Runnable() {
			public void run() {
				InputStreamReader ir = new InputStreamReader(System.in); // 键盘上输入的字节流转换成字符流
				BufferedReader br = new BufferedReader(ir);			     // 带缓冲区的字符流
				PrintStream ps = new PrintStream(pos); 
				
				while(true) {
					try {
						System.out.print(Thread.currentThread().getName()+"要求输入内容:");
						ps.println(br.readLine());	// 将从键盘读取的数据写入打印流里边对应的的管道流
						Thread.sleep(1000);			// 线程休眠
					} catch (Exception e) {
						e.printStackTrace();
					} 
				}
			}
		},"发送数据的线程").start();;
			
		
		// 再创建一个线程用来接收数据
		new Thread(new Runnable() {
			public void run() {
				InputStreamReader isr = new InputStreamReader(pis);	// 从管道流中读取数据,每读一行,输出一次
				BufferedReader br = new BufferedReader(isr);
				while(true) {
					try {
						System.out.println(Thread.currentThread().getName()+"收到的内容:"+br.readLine());
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		},"接收数据的线程").start();
	}

}

 创建PipedInputStream实例对象和PipedOutputStream实例对象,并通过connect()方法建立管道连接。然后开启两个线程,一个线程用于将键盘输入的数据写入管道输出流,一个线程用于从管道中读取写入的数据。从运行结果可以看出,通过管道,成功的完成了线程间的通信。

6.ByteArrayInputStream和ByteArrayOutputStream(字节数组流)

ByteArrayInputStream是从缓冲区中读取数据。

ByteArrayOutputStream会在创建对象时就创建一个byte型数组的缓冲区,当向数组中写数据时,该对象会把所有的数据先写入缓冲区,最后一次性写入文件。

import java.io.ByteArrayInputStream;
import java.io.IOException;

public class Test_ByteArrayInputStream {

	public static void main(String[] args) throws IOException {
		byte[] buff = new byte[] {1,2,3,4,5};
		ByteArrayInputStream bais = new ByteArrayInputStream(buff);	// 读取字节数组里的数据
		
		// 循环读取缓冲区中的数据
		int b;
		while((b = bais.read()) != -1) {
			System.out.println(b);
		}
		
		bais.close();

	}

}

通过构造方法ByteArrayInputStream(byte [ ]  b)创建了一个ByteArrayInputStream对象,从字节数组中每次读取一个字节,然后进行打印,通过运行结果可以看出,字节全部以字符的形式依次进行输出


import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test_ByteArrayInputStream {

	public static void main(String[] args) throws IOException {
		FileInputStream fis = new FileInputStream("D:\\JAVA Program\\FileReader.txt");
		ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 创建一个字节数组缓冲区
		FileOutputStream fos = new FileOutputStream("D:\\JAVA Program\\FileReaderes.txt");
	
		
		// 循环读取文件中的数据,并将数据保存在字节数组缓冲区中
		int b;
		while((b = fis.read()) != -1) {
			baos.write(b);
		}
	
		fos.write(baos.toByteArray()); // 将字节数组缓冲区里de数据一次性写入文件
		fis.close();
		baos.close();
		fos.close();
	
	}

}

定义了一个ByteArrayOutputStream对象,将文件中读取的字节全部写入该对象的缓冲区中,通过FileInputStream对象将缓冲区中的数据一次性写入目标文件。

7.CharArrayReader和CharArrayWriter(字符数组流)

CharArrayReader:是从字符数组中读取数据

CharArrayWriter:是在内存中创建一个字符数组缓冲区

import java.io.CharArrayReader;
import java.io.CharArrayWriter;
import java.io.FileReader;
import java.io.IOException;

public class Test_CharArrayWriter {

	public static void main(String[] args) throws IOException {
		FileReader fr = new FileReader("D:\\JAVA Program\\fileinputstream.txt");
		CharArrayWriter caw = new CharArrayWriter(); // 在内存中创建一个字符数组缓冲区
		
	//	将文件中的数据数据写入字符数组缓冲区
		int b;
		while((b = fr.read()) != -1) {
			caw.write(b);
		}
		fr.close();
		caw.close();
		
		
		char[] ch = caw.toCharArray();	//	将缓冲区中的数据转换成字符型数组
		CharArrayReader car = new CharArrayReader(ch); // 读取字符数组中的数据
		int a;
		while((a = car.read()) != -1) {
			System.out.print((char)a);
		}
		car.close();
		
	}

}

8.SequenceInputStream(序列流)

SequenceInputStream(序列流):是将多个读取流合并成一个读取流,实现数据合并。当通过这个流来读取数据时,它会依次从所有被串联的输入流中读取数据。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;

public class Test_SequenceInputStream {

	public static void main(String[] args) throws IOException {
	//	创建两个文件输入字节流对象
		FileInputStream fis1 = new FileInputStream("D:\\JAVA Program\\A.txt");
		FileInputStream fis2 = new FileInputStream("D:\\JAVA Program\\B.txt");
		
	//	创建一个序列流实现两个输入流合并
		SequenceInputStream sis = new SequenceInputStream(fis1, fis2);
		
	//	创建一个输出流
		FileOutputStream fos = new FileOutputStream("D:\\JAVA Program\\C.txt");
			
		int len;
		byte[] buff = new byte[1024]; // 创建一个字节数组缓冲区
		while(( len = sis.read(buff)) != -1) {
			fos.write(buff, 0, len);  // 将缓冲区中的数据写入文件
			fos.write("\r\n".getBytes()); // 将换行符、回车符(字符串)转换成字节写入到文件
		}
		
		sis.close();
		fos.close();
	}

}

五、File类

File类用于封装一个路径,路径可以是从系统盘符开始的绝对路径也可以是相对于当前目录而言的相对路径

File类内部封装的路径可以指向一个文件,也可以指向一个目录,在使用File类操作文件或者目录之前,首先得创建一个File对象。创建File对象的构造方法如下所示。

方法功能
File(String   path)

如果path是实际存在的路径,则该File对象表示的是目录;如果path是文件名,则该File对象表示的是文件。

File(String   path, String   name

path是路径名,name是文件名。

File(File dir,   String name

dir是路径对象,name是文件名。

1.File类的常用方法:

方法功能
String getName()获得文件的名称,不包括路径
String getPath()

获得文件的路径。

String getAbsolutePath()

获得文件的绝对路径。

File getAbsoluteFile( )

获得File对象的绝对路径文件

String getParent()

获得文件的上一级目录名。

boolean renameTo(File dest)

重命名File对象对应文件或目录

long lastModified()

返回File对象最后一次被修改的时间

long length()返回File对象所对应文件的长度(以字节为单位)
boolean exists()

测试当前File对象所表示的文件是否存在。

boolean delete()删除File对象对应的文件或目录,成功返回true,反之false
boolean createNewFile()当File对象对应的文件或目录不存在时,该方法将新建一个此File对象所指向的新文件,创建成功返回true,否则返回false
boolean canWrite判断File对象对应的文件或目录是否写,可写返回true,否则返回false
boolean canRead()判断File对象对应的文件或目录是否可读,可读返回true,反之false
boolean isFile()判断File对象对应的是否是文件(不是目录),是文件返回true,否则返回false
boolean isDirectory()判断File对象对应的是否是目录(不是文件),是返回true,反之返回false
boolean isAbsolute()判断File对象对应的文件或目录是否是绝对路径

boolean mkdir( )

创建当前File对象指定的目录。

String[ ]  lis()

返回当前目录下的文件和目录,返回值是字符串数组

String[] list(FilenameFilter filter)

返回当前目录下满足指定过滤器的文件和目录,参数是实现FilenameFilter接口对象,返回值是字符串数组。

File[] listFiles()

返回当前目录下的文件和目录,返回值是File数组。

File[] listFiles(FilenameFilter filter)

返回当前目录下满足指定过滤器的文件和目录,参数是实现FilenameFilter接口对象,返回值是File数组

File[] listFiles(FileFilter filter)

返回当前目录下满足指定过滤器的文件和目录,参数是实现FileFilter接口对象,返回值是File数组。

对目录操作有两个过滤器接口:FilenameFilterFileFilter。它们都只有一个抽象函数accept

FilenameFilter接口中的accept函数如下:

boolean accept(File dir, String name):测试指定dir目录中是否包含文件名为name的文件。

FileFilter接口中的accept函数如下:

boolean accept(File pathname):测试指定路径名是否应该包含在某个路径名列表中。

1.1.创建目录、文件

import java.io.*;
public class Day01 {

	public static void main(String[] args) throws IOException {
		File path1 = new File("D:\\JAVA Program\\day01"); 			// 定义File对象,表示目录
		File file1 = new File("D:\\JAVA Program\\day01\\day01.txt");// 定义File对象,表示文件
		path1.mkdir(); 		  // 调用mkdir()方法创建目录
		file1.createNewFile();// 调用creatNewFile()方法创建文件

	}
}

 

1.2.常用方法的实现

import java.io.*;
public class Day01 {

	public static void main(String[] args) throws IOException {
		File path1 = new File("D:\\JAVA Program\\day01"); 			 // 定义File对象,表示目录
		File file1 = new File("D:\\JAVA Program\\day01\\day01.txt"); // 定义File对象,表示文件
		
		
		path1.mkdir();			//	调用mkdir()方法创建目录
		file1.createNewFile();	//	调用creatNewFile()方法创建文件
			
		
		System.out.println("文件的名称:"+file1.getName());
		System.out.println("文件的路径:"+file1.getPath());
		System.out.println("文件的绝对路劲:"+file1.getAbsolutePath());
		System.out.println("File对象的绝对路径文件:"+file1.getAbsoluteFile());
		System.out.println("文件的上一级目录名:"+file1.getParent());
//		System.out.println("重命名File对象对应文件或目录:"+path1. renameTo(new File("D:\\JAVA Program\\day01\\day02.txt")));
		System.out.println("File对象最后一次被修改的时间:"+file1.lastModified());


		System.out.println("文件或目录是否存在?:"+path1.exists()+file1.exists());
//		System.out.println("删除File对象表示的文件:"+file1.delete());
		System.out.println("判断File对象表示的是否是目录:"+path1.isDirectory());
		System.out.println("判断File对象对应的目录是否是绝对路:"+path1.isAbsolute());
			
		
		System.out.println("返回当前目录下的文件和目录,返回值是字符串数组:");
		String[] list1 = path1.list();
		for(String lists : list1) {
			System.out.println(lists+" ");
		}
		
		System.out.println("返回当前目录下满足指定过滤器的文件和目录,参数是实现FilenameFilter接口对象,"
				+ "返回值是字符串数组。");
		String[] list2 = path1.list(new FilenameFilter(){

			// 创建FileNameFilter接口的对象(无名),称为匿名类,并作为参数传入到list()方法中
			
			public boolean accept(File dir, String name) {
				
				return (name.endsWith(".txt"));
			}
			
		});
		for(String lists : list2) {
			System.out.println(lists+" ");
		}	
	}
}

2.遍历目录下的文件

import java.io.File;

public class Test_File {

	public static void main(String[] args) {
		File file = new File("D:\\HBuilderProjects"); // 创建一个File对象
		
		if(file.isDirectory()) {  // 判断File对象对应的目录是否存在
			String[] filename = file.list(); // 获取目录下所有文件的文件名
			for(String name : filename) {
				System.out.println(filename);// 输出文件名
			}
			
		}

	}

}

创建了一个File对象封装了一个路径,通过调用FileisDirectory ()方法判断路径指向的是否为存在的目录,如果存在就调用list ()方法,获得一个String类型的filename数组,数组中包含这个目录下所有的文件的文件名。接着通过循环遍历,依次打印出每个文件的文件名.


如果希望获取指定类型的文件,可以使用重载的list(FilenameFilter)方法。 list(FilenameFilter filter)方法的工作原理如下所示:

1、调用list()方法传入FilenameFilter文件过滤器对象

2、取出当前File对象所代表目录下的所有子目录和文件

3、对于每一个子目录或文件,都会调用文件过滤器对象的accept(File dir,String name)方法,并把代表当前目录的File对象以及这个子目录或文件的名字作为参数dirname传递给方法

4、如果accept()方法返回true,就将当前遍历的这个子目录或文件添加到数组中,如果返回false,则不添加。

import java.io.File;
import java.io.FilenameFilter;

public class Test_File_2  {

	public static void main(String[] args) {
		File file = new File("D:\\JAVA Program\\字符流");
		
		//	创建过滤器对象
		FilenameFilter filter = new FilenameFilter() {
			//	实现accept方法
			public boolean accept(File dir, String name) {
				File currFile = new File(dir,name);
				
				//	如果文件名以.java结尾返回true,反之false
				if(currFile.isFile() && name.endsWith(".java"))
					return true;
				else
					return false;
					
			}
		};
		
		if(file.exists()) {// 判断File对象对应的目录是否存在
			String[] lists = file.list(filter); // 获得过滤后的所有文件名数组
			for(String name : lists) {
				System.out.println(name);
			}
		}

	}

}

定义了一个静态方法fileDir (),方法接收一个表示目录的File对象。在方法中,首先通过调用listFiles()方法把该目录下所有的子目录和文件存到一个File类型的数组files中,接着遍历数组files,对当前遍历的File对象进行判断,如果是目录就重新调用fileDir ()方法进行递归,如果是文件就直接打印输出文件的路径,这样该目录下的所有文件就被成功遍历出来了

2.删除文件及目录

File类提供了delete()方法删除文件,但该方法无法删除目录,因此,要想删除文件及目录,需要通过递归的方式将整个目录以及其中的文件全部删除

import java.io.File;

public class Test_Delete {

	public static void main(String[] args) {
		File file = new File("D:\\JAVA Program"); // 创建一个代表目录的File对象
		deleteDir(file); // 调用delete删除方法
	
	}
	
	
	public static void deleteDir(File dir) {
		if(dir.exists()) {  //	判断传入File对象是否存在
			File[] files = dir.listFiles();	// 得到File数组
			for(File file : files) {  //  遍历所有的子目录和文件
				if(file.isDirectory()) {
					deleteDir(file); // 如果是目录,递归调用deletedir方法
				}
				else {
					// 如果是文件,则直接删除
					file.delete();
				}
			}
			
			dir.delete();	// 删除完一个目录里的所有文件后,就删除这个目录
		}
	}

}

定义了一个删除目录的静态方法deleteDir(),接收一个File类型的参数。在这个方法中,调用listFiles()方法把这个目录下所有的子目录和文件保存到一个File类型的数组files中,然后遍历files,如果是目录就重新调用deleteDir()方法进行递归,如果是文件就直接调用Filedelete()方法删除。当删除完一个目录下的所有文件后,再删除当前这个目录,这样便从里层到外层递归的删除了整个目录.

六、RandomAccesseFile

  •  RandomAccesseFile不属于流类,但具有读写文件数据的功能,可以随机地从文件的任何位置开始执行读写数据的操作
  • RandomAccessFile可以将文件以只读或者读写的方式打开具体使用哪种方式取决于创建它所采用的构造方法
方法功能
RandonAccessFile(File file, String mode)参数file指定被访问的文件
RandonAccessFile(String name, String mode)参数name指定被访问文件的路径

RandomAccessFile对象的两个构造方法。通过这两种方法创建RandomAccessFile对象时,都需要接受两个参数,第一个参数指定关联的文件,第二个参数mode指定访问文件的模式。参数mode有四个值,最常用的有两个,分别是“r“和“rw”,其中“r”表示以只读的方式打开文件,如果试图对RandomAccessFile对象执行写入操作,会抛出IOException异常,“rw”表示以“读写”的方式打开文件,如果该文件不存在,则会自动创建该文件。


RandomAccessFile类提供了一些用于定位文件位置的方法:

方法功能
long getFilePointer()返回当前读写指针所处的位置
void seek(long pos)设定读写指针的位置,与文件开头相隔pos个字节数
int skipBytes(int  n)使读写指针从当前位置开始,跳过n个字节
void setLength(long newLength)设置此文件的长度

 RandomAccessFile对象中包含了一个记录指针,用于表示文件当前读写处的位置。当新创建一个RandomAccessFile对象时,该对象的文件记录指针位于文件头(也就是0),当读写了n个字节后,文件的记录指针就会向后移动n个字节。RandomAccessFileseek(long pos)方法,可以使记录指针向前、向后自由移动,通过RandomAccessFilegetFilePointer()方法,便可获取文件当前记录指针的位置。


RandomAccessFile类实现记录软件试用次数的过程:

import java.io.IOException;
import java.io.RandomAccessFile;

public class Test_RandomAccesseFile {

	public static void main(String[] args) throws IOException {
		
		RandomAccessFile raf = new RandomAccessFile("D:\\JAVA Program\\A.txt", "rw");
		
		int times = 0; // times表示试用次数
		times = Integer.parseInt(raf.readLine()); // 第一次读取文件时times为5
		if(times > 0) {
			// 试用一次,次数减少一次
			System.out.println("您可以试用" + times-- + "次!");
			raf.seek(0);  // 使记录指针指向文件的开头
			raf.writeBytes(times+""); // 将剩余次数写入文件
		}
		else {
			System.out.println("软件试用次数已用完");
		}
		
		raf.close();
	}

}

在当前目录下创建了一个RandomAccessFile对象关联访问的文件“A.txt”,并设置了“rw”的访问模式。在使用软件时,使用变量times记录软件能够试用的次数,第一次读取文件时,times的值为5次。用户每次试用软件后,软件会把试用次数减1(times--),同时提示用户剩余试用次数,然后通过调用raf.seek(0)方法把文件的记录指针跳转到文件头的位置,将剩余的次数重新写入文件。当表示试用的次数times<=0时,则提示用户的试用次数已到。最后关闭RandomAccessFile对象(raf.close()),便完成了软件试用的功能。

七、字符编码

字符码表是一种可以方便计算机识别的特定字符集,它是将每一个字符和一个唯一的数字对应而形成的一张表

1.字符编码和解码

编码把字符串转换成计算机识别的字节序列

解码把字节序列转换为普通人能看懂的明文字符串

import java.io.IOException;
import java.util.Arrays;

public class Test_bianma {

	public static void main(String[] args) throws IOException {
		
		String str = "你好";
		byte[] b1 = str.getBytes();       // 使用默认的码表编码
		byte[] b2 = str.getBytes("GBK");  // 使用GBK编码
		byte[] b3 = str.getBytes("UTF-8");// 使用UTF-8编码
		
	// 把字节数组中的数据以数组字符串的形式打印	
		System.out.println(Arrays.toString(b1));
		System.out.println(Arrays.toString(b2));
		System.out.println(Arrays.toString(b3));
		
		
		
	// 对字节数组里边的字节序列进行解码,并以明文字符串形式输出
		String result1 = new String(b1,"GBK");
		System.out.println(result1);
		String result2 = new String(b2,"GBK");
		System.out.println(result2);
		String result3 = new String(b3,"UTF-8");
		System.out.println(result3);
		String result4 = new String(b2,"ISO8859-1");
		System.out.println(result4);
	}

}

29行尝试使用ISO8859-1码表对GBK编码的数组进行解码时,出现了四个问号,这是由编码和解码时使用的码表不一致所造成的乱码问题。


 乱码:是由于编码和解码方式不一致导致的问题

import java.io.IOException;

public class Test_biamma_2 {

	public static void main(String[] args) throws IOException {
		
		String str = "你好";
		byte[] b = str.getBytes("GBK"); // 使用GBK进行编码
		
		
		String str1 = new String(b, "UTF-8"); // 使用错误的码表解码,打印出了乱码
		System.out.println(str1);
		
		String str2 = new String(b, "GBK");   // 正确的码表编码
		System.out.println(str2);
		
	}

}

 

2.字符传输

通过构造方法InputStreamReader(InputStream is,String charsetName)OutputStreamReader(OutputStream os,String charsetName)创建流对象时,可以对需要读写的数据指定编码格式.

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Test_inputStreamoutputStream {

	public static void main(String[] args) throws IOException {
	//	创建输入、输出流对象	
		FileInputStream fis = new FileInputStream("D:\\JAVA Program\\A.txt");
		InputStreamReader isr = new InputStreamReader(fis,"GBK");     
		
		FileOutputStream fos = new FileOutputStream("D:\\JAVA Program\\D.txt");
		OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8"); 
		
		char[] ch = new char[100];// 定义一个字符数组
		int len;		          // 记录读取的字符个数
		len = isr.read(ch);       // 将文件的内容读取到字符数组
		
		String str = new String(ch,0,len); // 使用字符数组创建字符串
		osw.write(str);    				   // 向目标文件写入字符串
		
		isr.close();
		osw.close();
	}
}

创建了FileInputStreamReaderFileOutputStreamWriter对象时,构造函数中分别传入了“GBK”码表“UTF-8”码表,这样,当读取编码格式为GBK的文件时,就能正确地将字节转换成字符。当写入编码格式为UTF-8的文件时,字符也可以正确的转换成对应的UTF-8字节,从而避免了程序在读写操作时的乱码问题.

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来得晚一些也行

观众老爷,请赏~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值