1、File类
File这个类,在命名上多少有些误导。实际上, File不只可以 表示一个文件,还可以表示一个路径(可以理解为文件夹)。
通过建立File对象,我们就可以操作具体的某个(些)文件 (文件夹)。
2、File类构造器
public File(String path)
如果path是实际存在的路径,则该File对象表示的是目录 如果path是文件名,则该File对象表示的是文件
File dir = new File("C:/io/File.java");
public File(String path, String name)
path是路径名, name是文件名或路径名
File myfile = new File("C:/io", "File.java");
public File(File dir, String name)
dir是路径名, name是文件名
File myDir = new File("C:/io");
File myFile = new File(myDir, "File.java");
3、File 常用方法
/*
* File类相关方法
* 创建一个File对象,是不会在硬盘上生成对应的文件或
* 目录(文件夹)的,我们需要调用相关的方法来创建文件
* 或目录。
*
* mkdir与mkdirs方法
* 两个方法都用来创建路径(文件夹),不同的是,当路径所在
* 的父路径不存在时,mkdir不会创建成功,返回false,而
* mkdirs会连同父路径一同创建。
*/
package day16;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class FileMethod {
public static void main(String[] args) throws IOException {
File file = new File("c:/1234.txt");
// File file = new File("1234.txt");
// 生成File对象所表示的文件。文件所在的路径必须
// 存在,才能创建成功。否则会产生IOException异常。
// file.createNewFile();
// 返回文件的名字
System.out.println(file.getName());
// 返回文件的路径
System.out.println(file.getPath());
// 返回文件的绝对路径。
System.out.println(file.getAbsolutePath());
// 返回上级路径
System.out.println(file.getParent());
// 判断文件是否存在,存在返回true,否则返回false。
System.out.println(file.exists());
// 判断文件是否可写,是返回true,否则返回false。
System.out.println(file.canWrite());
// 判断文件是否可读,是返回true,否则返回false。
System.out.println(file.canRead());
// 判断当前file对象表示的是否为文件,是则返回true,
// 否则返回false。
System.out.println(file.isFile());
// 判断当前file对象表示的是否为路径(目录),是
// 则返回true,否则返回false。
System.out.println(file.isDirectory());
// 返回文件最后一次的修改时间。
long time = file.lastModified();
Date d = new Date(time);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(df.format(d));
// 返回文件的长度,以字节为单位。
System.out.println(file.length());
// 删除file对象所表示的文件,成功返回true,否则返回false。
System.out.println(file.delete());
File f2 = new File("c:");
// f2.createNewFile();
// 创建File对象所代表的路径。成功返回true,否则
// 返回false。
// 调用mkdir创建路径时,该路径所在的父路径必须要
// 存在,否则无法创建成功,返回false。
// System.out.println(f2.mkdir());
// 创建File对象所代表的路径,成功返回true,否则
// 返回false。
// 调用mkdirs创建路径时,如果该路径所在的父路径
// 不存在,则连同父路径一同创建。
// System.out.println(f2.mkdirs());
// 返回当前File对象所表示的路径下所有的文件与路径(名字)。
String[] names = f2.list();
for (String name : names) {
System.out.println(name);
}
// 返回当前File对象所表示的路径下所有的文件与路径(File对象)
File[] files = f2.listFiles();
for (File f : files) {
System.out.println(f.getName() + ":" + f.lastModified());
}
}
}
4、流
流是一组有顺序的、有起点和终点的数据。 Java程序的输入输出功能是通过流(stream)来实现的。 在Java中有关流的操作类存放在java.io包中
输入流用来读取文件,输出流用来写入文件。
当程序需要读取数据的时候,就会开启一个通向数据源的流, 这个数据源可以是文件,内存,或是网络连接。类似的,当 程序需要写入数据的时候,就会开启一个通向目的地的流 。
5、流的分类
流按照处理数据的单位可以分为两种:
字节流( 8位)
字符流( 16位)
二进制文件的基本存储单位是字节
文本文件的基本存储单位是字符
6、字节流和字符流
字节流用于处理字节的输入和输出。例如使用字节流读取或 写入二进制数据。
字符流为字符输入和输出处理提供了方便,在某些场合,字 符流比字节流更高效。
字节流的父类是InputStream与OutputStream。字符流的父 类是Reader与Writer
7、InputStream类
int read() 读取一个字节,返回值为所读的字节。
int read(byte[ ] b) 读入b.length个字节到数组b并返回实际 读入的字节数。
int read(byte[ ] b, int off, int len) 读入流中的数据到数组b, 从off开始的长度为len的数组元素中。
int avaliable() 返回当前输入流中可读的字节数。
close() 流操作完毕后必须关闭。
说明:如果到了文件的末尾,以上三个方法均返回-1。
/*
* 字节输入流读取文件
*/
package day16;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class InputStreamTest {
public static void main(String[] args) {
try {
String path = "D:/eclipse/workspace/java/src/day16/FileMethod.java";
// 使用输入流读取文件,该文件必须要存在,否则会产生
// FileNotFoundException异常。
InputStream in = new FileInputStream(path);
// 读取一个字节,返回读取到的字节(无符号)。
// 如果没有字节可读,返回-1。
// int data = in.read();
// while (data != -1) {
// System.out.print((char) data);
// // 读取下一个字节。
// data = in.read();
// }
// 改进
// int data;
// while ((data = in.read()) != 1) {
// System.out.print((char) data);
// }
// 通过数组方式实现
byte[] data = new byte[10];
int length;
// 读取的数据放到字节数组当中。尽可能填满整个数组。
// 当填满数组或没有数据可读时,返回实际读取的字节数。
// 当没有数据可读时,返回-1。
// while ((length = in.read(data)) > 0) {
// for (int i = 0; i < data.length; i++) {
// System.out.print((char)data[i]);
// }
// 使用字节数组的所有元素(数据)去构造String对象。
// String s = new String(data);
// 使用字节数组(区间)去构造String对象。
// 第2个参数指定偏移量,第三个参数指定元素的长度。
// String s = new String(data, 0, length);
// System.out.print(s);
// }
// 使用字节数组的一部分(区间)实现
// 使用字节数组的部分(区间)来存储读取的数据。第二个参数指定
// 偏移量,第三个参数指定长度。当区别填满或无数据可读时,返回
// 实际读取的字节数,如果无数据可读,返回-1。
while ((length = in.read(data, 0, 5)) > 0) {
String s = new String(data, 0, length);
System.out.print(s);
}
// 可以释放资源,但如果之前产生异常,该语句
// 将不会得到执行,导致资源无法释放。造成
// 资源泄露。
// in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
8、对资源释放
/*
* 对资源的释放
* 虽然finally总是会得到执行,但是,在finally中
* 对资源进行释放过于繁琐。我们可以考虑使用try-with-resources
* 来自动释放资源。
*
* try (声明需要释放的资源) {
* 可能产生异常的语句
* } catch (异常) {
*
* }
* try-with-resources的优势在于:声明在小括号中的资源,可以
* 在try语句块执行完毕后得到自动的释放(自动调用该资源的close方法)。
* 只有AutoCloseable类型(子类型)才能作为try-with-resources
* 的资源。
*/
package day16;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class CloseTest {
public static void main(String[] args) {
String path = "D:/eclipse/workspace/java/src/day16/FileMethod.java";
InputStream in = null;
try {
in = new FileInputStream(path);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 使用try-with-resources自动释放资源,简化操作。
try (InputStream in2 = new FileInputStream(path)) {
// 读取文件的操作
// in2.read();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
9、实现复制
/*
* 使用字节输入流与字节输出流实现文件的复制。
*/
package day16;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Copy {
public static void main(String[] args) {
try (InputStream in = new FileInputStream("c:/第15天.pdf");
OutputStream out = new FileOutputStream("c:/第15天copy.pdf")) {
// 返回流中可读取的字节数。
System.out.println(in.available());
int data;
while ((data = in.read()) != -1) {
out.write(data);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
10、OutputStream类
void write(int b ) 往流中写一个字节b。
void write(byte b[ ]) 往流中写一个字节数组b。
void write(byte b[ ], int off, int len) 把字节数组b中从下标 off开始,长度为len的字节写入流中。
flush( ) 刷新输出流,并输出所有被缓存的字节,由于某些 流支持缓存功能,该方法将把缓存中所有内容强制输出到流 中。
close( ) 流操作完毕后必须关闭。
/*
* 字节输出流
* 输入流与输出流(文件不存在时对比)
* 对于输入流,如果文件不存在,则会产生
* FileNotFoundException异常。
* 对于输出流,如果文件不存在,但是文件所在的路径存在,
* 则该文件会被自动创建。如果文件不存在,文件所在的路径
* 也不存在,则会产生FileNotFoundException异常。
*/
package day16;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamTest {
public static void main(String[] args) {
try (OutputStream out = new FileOutputStream("c:/1234.txt");) {
// 写入一个字节
// out.write(65);
// 写入一个字节数组(写入数组中所有的元素)
byte[] data = { 65, 66, 67, 68, 69, 70 };
// out.write(data);
// 写入数组的一个区间(第2个参数指定开始位置,
// 第3个参数指定长度)
out.write(data, 1, 2);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
11、Reader类
public int read() throws IOException 读取一个字符,返回 值为读取的字符。
public int read(char cbuf[ ]) throws IOException 读取一系 列字符到数组cbuf[]中,返回值为实际读取的字符的数量。
public abstract int read(char cbuf[],int off,int len) throws IOException 读取len个字符,从数组cbuf[]的下标off处开始 存放,返回值为实际读取的字符数量。
public abstract void close() throws IOException 关闭流。
说明:三个read方法如果已到达流的末尾,则返回 -1。
12、Writer类
public void write(int c) throws IOException 将整型值c的低 16位写入输出流。
public void write(String str) throws IOException 将字符串 str中的字符写入输出流。
public void write(char cbuf[]) throws IOException 将字符 数组cbuf[]写入输出流。
public abstract void write(char cbuf[],int off,int len)
throws IOException 将字符数组cbuf[]中的从索引为off的位 置处开始的len个字符写入输出流。
public void write(String str,int off,int len) throws
IOException 将字符串str 中从索引off开始处的len个字符写 入输出流。
flush() 刷新输出流,并输出所有被缓存的字节。
close() 关闭流。
/*
* 字符流
*/
package day16;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
public class ReadWriterTest {
public static void main(String[] args) throws IOException {
Writer w = new FileWriter("c:/1234.txt");
w.write("写String");
// 刷新缓存中的数据,将缓存中的数据传输到目的地。
// w.flush();
// 当我们调用close方法关闭流资源时,会自动刷新缓存。
// 即会调用流的flush方法。
w.close();
}
// 使用字符流也可以实现文件的复制。
public void copy(String src, String dst) {
try (Reader reader = new FileReader(src); Writer writer = new FileWriter(dst)) {
char[] data = new char[10];
int length;
while ((length = reader.read(data)) > 0) {
writer.write(data, 0, length);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
13、标准输入输出
public static final InputStream in :
标准输入,从标准输入获取输入(通常是键盘)
public static final PrintStream out :
标准输出,把输出送到缺省的显示(通常是显示器)
public static final PrintStream err :
标准输出,把错误信息送到缺省的显示
/*
* System类中的in,out,err
* out与err都是输出流(PrintStream),
* 区别在于:
* System.out是执行正常输出的。
* System.err是执行异常输出的。
*
* 使用System类的setIn,setOut,setErr方法可以实现
* IO流的重定向,这有利于我们对信息进行分类处理。
*/
package day16;
import java.io.IOException;
import java.io.PrintStream;
public class SystemTest {
public static void main(String[] args) throws IOException {
// System.out.println("正常输出");
// System.err.println("异常输出");
PrintStream p = new PrintStream("c:/error.txt");
// 错误流重定向
System.setErr(p);
System.out.println("输出标准正常的信息。");
System.err.println("输出错误的信息!");
}
}
14、字符流
主要用来读写字符串数据,即文本数据。
二进制文件与文本文件的区别 文件最终都是以二进制的形式存储,如果一个文件中的每个字 节或每相邻的几个字节的数据都可以表示成某种字符,这样的 文件就是文本文件,可见文本文件只是二进制文件的一种,如 mp3、图像的文件就不能转换成字符,而txt文件里面存储的都 是字符。
15、读写文件
InputSteam类、 OutputSteam类、 Reader类和Writer类都是 抽象的,无法创建该类的对象,我们需要使用子类来进行相 关操作。
FileInputSteam与FileOutputSteam继承InputSteam与 OutputSteam。而FileReader与FileWriter继承Reader与 Writer。
/*
* 使用输出流时,可以指定是否以追加的形式写入数据。
* 如果追加,会在文件末尾继续写入,
* 如果不追加,则会覆盖文件,重新写入。
*/
package day16;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class AppendTest {
public static void main(String[] args) {
// 指定以追加的方式写入数据,默认为false(覆盖)。
try (OutputStream out = new FileOutputStream("c:/1234.txt", true);) {
out.write(65);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
16、FileInputStream类构造器
FileInputStream对象封装了将要读取的文件,读文件必须存在 且包含数据,该类类型的构造器只能为存在的文件创建对象。
FileInputStream(String filename) 从String对象创建 FileInputStream对象,该String对象用来指定文件名,该构 造方法会抛出FileNotFoundException异常。
FileInputStream in = new FileInputStream("fileIn.txt");
FileInputStream(File file) 使用File对象进行创建,也会抛出 FileNotFoundException异常。
File file = new File("c:\\tmp\\test.txt");
FileInputStream in = new FileInputStream(file);
17、FileOutputStream类构造器
FileOutputStream(String filename) 为文件filename创建一 个输出流,文件中存在的内容将被覆盖。
FileOutputStream(String filename,boolean append) 创建一 个文件输出流对象,并将内容写到指定的filename文件中, 如果append为true,则接着文件最后写,否则文件中的内容
将被覆盖。
FileOutputStream(File file) 为对象file表示的文件创建一个 输出流,文件中的内容将被覆盖。
FileOutputStream(File file, boolean append)
创建一个文件输出流对象,并将内容写到指定的file对象中,如 果append为true,则接着文件最后写,否则文件中的内容将被 覆盖。
说明:如果该文件不存在,则创建一个同名的新文件,但只有 在父目录存在的条件下创建,操作才会执行,所以使用前最后 检查下父目录是否存在。
18、缓存流
BufferedReader 缓存输入流
BufferedWriter 缓存输出流
使用缓存流可以使字符流读取(写入)更加高效。
/*
* 缓存流
* BufferedReader
* BufferedWriter
*
* 使用缓存可以减少程序与底层IO设备进行交互的次数,
* 进而提高性能。(与底层IO设备进行交互是一个耗时的操作)。
*
* 在进行输出是优先使用PrintWriter,因为其输出方法
* print不会产生异常(异常内部处理)。
*/
package day16;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class BufferedTest {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("c:/1234.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("c:/5678.txt"))) {
String s;
// 一次读取一行。当没有数据可读时,返回null。
while ((s = br.readLine()) != null) {
bw.write(s);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try (BufferedReader br = new BufferedReader(new FileReader("c:/1234.txt"));
PrintWriter pw = new PrintWriter("c:/5678.txt")) {
String s;
// 一次读取一行。当没有数据可读时,返回null。
while ((s = br.readLine()) != null) {
// pw.write(s);
pw.print(s);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
19、转换流
Java提供两个转换流,用于将字节流转换成字符流。
InputSteamReader 字节输入流转换为字符输入流。
OutputSteamWriter 字节输出流转换为字符输出流。
说明:当对字符进行读取,写入时,将字节流转换成字符流可
以提高效率。
package day16;
import java.awt.Insets;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
public class TransfromTest {
public static void main(String[] args) {
}
public void f(InputStream in, OutputStream out) {
// 将字节流转换成字符流,但是不太方便。
InputStreamReader is = new InputStreamReader(in);
OutputStreamWriter os = new OutputStreamWriter(out);
// 更加高效的操作,使用缓存流再进行一次包裹。
// BufferedReader br = new BufferedReader(is);
// PrintWriter pw = new PrintWriter(os);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
// PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
PrintWriter pw = new PrintWriter(out);
}
}
20、数据流
数据流是对基本数据类型与String类型的进行输入输出操作。 数据流需要实现DataInput与DataOutput接口。最常使用的 数据流是DataInputStream与DataOutputStream。
使用数据流可以操作基本数据类型与String类型。
/*
* 数据流
* 数据流支持的类型是基本数据类型与String类型。
* 写入数据调用的方法:writeT,T为相关的类型。
* String对应的方法是writeUTF。
*/
package day16;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataStreamTest {
public static void main(String[] args) {
DataStreamTest d = new DataStreamTest();
// d.write();
d.read();
}
public void write() {
int[] x = { 3, 10, 20, 354 };
String[] s = { "kk", "xc", "323", "vadf" };
try (DataOutputStream out = new DataOutputStream(new FileOutputStream("c:/data.txt"));) {
for (int i = 0; i < x.length; i++) {
out.writeInt(x[i]);
out.writeUTF(s[i]);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void read() {
// 数据流没有办法判断是否还有数据可以读取,只能靠
// 捕获EOFException来结束。(当无数据可以读取时,
// 会抛出EOFException异常。)
try (DataInputStream input = new DataInputStream(new FileInputStream("c:/data.txt"));) {
while (true) {
// 使用数据流读取时需要注意,读取的顺序与写入
// 时的顺序一致。
System.out.print(input.readInt());
System.out.println("-" + input.readUTF());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (EOFException e) {
System.out.println("文件到达末尾,读取完毕,捕获异常。");
} catch (IOException e) {
e.printStackTrace();
}
}
}
21、对象流
对象流是对对象进行的输入输出操作。我们使用 ObjectInputStream与ObjectOutputStream类来实现对象的读 取与写入。以上两个类分别实现ObjectInput与ObjectOutput接 口( DataInput 与DataOutput的子接口)。
把Java对象转换为字节序列称为序列化,而把字节序列恢复 为Java对象称为反序列化。对象序列化需要实现Serializable 接口。
Serializable接口没有显式声明任何方法,是一个标记接口。
/*
* 对象流
*/
package day16;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class ObjectStreamTest {
public static void main(String[] args) {
ObjectStreamTest o = new ObjectStreamTest();
// o.write();
o.read();
}
public void read() {
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("c:/object.txt"))) {
// 从流中恢复之前保存的对象(对象反序列化)
Person p = (Person) in.readObject();
// System.out.println(p.getName());
// System.out.println(p.getAge());
Person p2 = (Person) in.readObject();
// 如果写入时,同一个对象写入多次,则读取时,
// 也只有一个对象。
System.out.println(p == p2);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public void write() {
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("c:/object.txt"))) {
Person p = new Person("张三", 30);
// 序列化对象
out.writeObject(p);
out.writeObject(p);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 将对象序列化,则该对象必须要实现Serializable接口。
// 该接口没有任何方法,是一个标记接口。
class Person implements Serializable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
}