二、字节流大多数应用程序都需要实现与设备之间的数据传输,例如,键盘可以输入数据,显示器可以显示程序的运行结果等
在Java中,将这种通过不同输入/输出设备(键盘,内存,显示器,网络等)之间的数据传输抽象表述为“流”,程序允许通过流的方式与输入/输出设备进行数据传输
Java中的“流”都位于java.io包中,称为IO(输入/输出)流
IO流有很多种,按照操作数据的不同,可以分为字节流和字符流,按照数据传输方向的不同又可分为输入流和输出流,程序从输入流中读取数据,向输出流中写入数据。
1.InputStream的方法:在计算机中,无论是文本、图片、音频还是视频,所有的文件都是以二进制(字节)形式存在,IO流中针对字节的输入输出提供了一系列的流,统称为字节流。
在JDK中,提供了两个抽象类InputStream和OutputStream,它们是字节流的顶级父类,所有的字节输入流继承自InputStream,所有的字节输出流都继承自OutputStream。
| 方法 | 功能 |
| 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() | 关闭输入流并释放与此流相关的系统资源 |
| 方法 | 功能 |
| 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() | 刷新输出流并清空缓存区 |
- 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
通过运行结果可以得知,如果是通过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
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包中提供两个带缓冲的字节流,分别是BufferedInputStream和BufferdOutputStream,这两个流都使用了装饰设计模式。它们的构造方法中分别接收InputStream和OutputStream类型的参数作为被包装对象,在读写数据时提供缓冲功能。
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();
}
}
BufferedInputStream和BufferedOutputStream两个缓冲流对象,这两个流内部都定义了一个大小为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.字符缓冲流
字符流提供了带缓冲区的包装流,分别是BufferedReader和BufferedWriter,其中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("rn");
}
fw.close();
lb.close();
}
}
在拷贝过程中,使用LineNumberReader类跟踪行号,首先调用setLineNumber()方法设置行号的初始值,本例中将行号起始值置为0。从运行结果可以看出,调用getLineNumber()方法读取行号时,行号是从1开始的。这是因为LineNumberReader类在读取到换行符('n')、回车符('r')或者回车后紧跟换行符时,会将行号自动加1。
4.转换流
转换流是一种包装流。
OutputStreamWriter是Writer的子类,可以将一个字节输出流包装成字符输出流,方便直接写入字符,
InputStreamReader是Reader的子类,它可以将一个字节输入流包装成字符输入流,方便直接读取字符。
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
DataInputStream和DatOutputStream是两个与平台无关的数据操作流。
它们不仅提供读写各种基本类型数据的方法,而且还提供了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格式的数据,然后通过DataInputStream的readChar()、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("男");
}
}
PrintStream的print()和println()方法区别在于println()方法在输出数据的同时还输出了换行符。
4.标准输入输出流
- 在System类中定义了三个常量:in、out和err,它们被习惯性地称为标准输入输出流。
- in为InputStream类型,它是标准输入流,默认情况下用于读取键盘输入的数据。
- out为PrintStream类型,它是标准输出流,默认将数据输出到命令行窗口。
- err也是PrintStream类型,它是标准错误流,它和out一样也是将数据输出到控制台,它输出的是应用程序运行时的错误信息
5.PipedInputStream和PipedOutputStream
PipedInputStream和PipedOutputStream称作管道流,它是一种比较特殊的流,必须先建立连接才能进行彼此间通信。
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("rn".getBytes()); // 将换行符、回车符(字符串)转换成字节写入到文件
}
sis.close();
fos.close();
}
}
五、File类
File类用于封装一个路径,该路径可以是从系统盘符开始的绝对路径,也可以是相对于当前目录而言的相对路径
File类内部封装的路径可以指向一个文件,也可以指向一个目录,在使用File类操作文件或者目录之前,首先得创建一个File对象。创建File对象的构造方法如下所示。
方法 功能 File(String pathname) 通过路径名创建一个新的File实例 File(String parent, String child) 根据父目录路径和子目录或文件路径创建一个新的File实例 File(File parent, String chid) 根据父目录路径File实例和子目录或文件路径创建一个新的File实例
1.File类的常用方法:
方法 功能 boolean exists() 判断File对象对应的文件或目录是否存在,存在返回true,反之false boolean delete() 删除File对象对应的文件或目录,成功返回true,反之false boolean createNewFile() 当File对象对应的文件或目录不存在时,该方法将新建一个此File对象所指向的新文件,创建成功返回true,否则返回false String getName() 返回File对象对应的文件或文件夹名称 String getPath() 返回File对象对应的路径 String getAbsolutePath() 返回File对象对应的绝对路径 String getParent() 返回File对象对应的目录的父目录 boolean canWrite 判断File对象对应的文件或目录是否写,可写返回true,否则返回false boolean canRead() 判断File对象对应的文件或目录是否可读,可读返回true,反之false boolean isFile() 判断File对象对应的是否是文件(不是目录),是文件返回true,否则返回false boolean isDirectory() 判断File对象对应的是否是目录(不是文件),是返回true,反之返回false boolean isAbsolute() 判断File对象对应的文件或目录是否是绝对路径 long lastModified() 返回时间戳 long length() 返回文件内容的长度 String[ ] list 列出指定目录的全部内容(只是列出名称) File[ ] listFiles() 返回一个包含File对象所有子文件和子目录的File数组
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对象封装了一个路径,通过调用File的isDirectory ()方法判断路径指向的是否为存在的目录,如果存在就调用list ()方法,获得一个String类型的filename数组,数组中包含这个目录下所有的文件的文件名。接着通过循环遍历,依次打印出每个文件的文件名.
如果希望获取指定类型的文件,可以使用重载的list(FilenameFilter)方法。 list(FilenameFilter filter)方法的工作原理如下所示:
1、调用list()方法传入FilenameFilter文件过滤器对象
2、取出当前File对象所代表目录下的所有子目录和文件
3、对于每一个子目录或文件,都会调用文件过滤器对象的accept(File dir,String name)方法,并把代表当前目录的File对象以及这个子目录或文件的名字作为参数dir和name传递给方法
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()方法进行递归,如果是文件就直接调用File的delete()方法删除。当删除完一个目录下的所有文件后,再删除当前这个目录,这样便从里层到外层递归的删除了整个目录.
六、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个字节。RandomAccessFile的seek(long pos)方法,可以使记录指针向前、向后自由移动,通过RandomAccessFile的getFilePointer()方法,便可获取文件当前记录指针的位置。
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();
}
}
创建了FileInputStreamReader和FileOutputStreamWriter对象时,构造函数中分别传入了“GBK”码表和“UTF-8”码表,这样,当读取编码格式为GBK的文件时,就能正确地将字节转换成字符。当写入编码格式为UTF-8的文件时,字符也可以正确的转换成对应的UTF-8字节,从而避免了程序在读写操作时的乱码问题.



