File类型
所在包:java.io.File
作用:可以对文件或目录操作,如查看文件或目录的属性信息、创建,删除文件或目录。不能对文件的内容进行访问。如果需要访问文件里的内容,则需要使用输入/输出流
常用构造器:
1. File(String pathname) 通过指定的路径创建一个File对象
File f1=new File("D:"+File.separator+"file1.txt");
抽象路径应该尽量使用相对路径,并且目录的层级分隔符尽可能不要直接写"/"或者"\",应该使用File.separator这个常量表示,以避免不同系统带来的差异。
File f2=new File(".\\file2.txt"); //两个反斜杠为转义字符,相当于"\"
ile2.txt在当前项目的文件夹中
构造器中指定的路径字符串,如果不是从根路径下开始写的,那么都是相对路径相对于项目名(当前目录.相当于项目名目录)。
2. File(String parent,String child) 通过指定父路径和子路径来创建一个File对象
File f3=new File("D:\\d1","file3.txt");
f3绝对路径为 D:\d1\file3.txt
3. File(File parent,String child) 通过指定File对象描述的路径和子路径,创建新File对象
File f4=new File(new File("D:\\d2"),"file4.txt");
f4绝对路径为D:\d2\file4.txt
文件和目录操作相关方法
- String[] list() 返回一个字符串数组,命名由此抽象路径名表示的目录中的文件和目录
- String[] list(FilenameFilter filter) 过滤文件和目录。true:表示获取的文件和目录;alse:表示要过滤不要的文件和目录。
File f1=new File(".");
String[] fs1=f1.list(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith(".");
}
});
for(String s:fs1){
System.out.println(s);
}
f1获取当前项目目录,过滤获取文件名以"."开头的文件,结果为
.classpath
.project
.settings
- File[] listFiles() 返回一个抽象路径名数组,表示由该抽象路径名表示的目录中的文件
- boolean delete() 删除目录时,必须保证此目录下是空目录
使用递归方法删除非空目录
public static void delDir(String pathname) {
File file = new File(pathname);
if(file.exists()) {
if(file.isDirectory()) {
File[] fs = file.listFiles();
if(fs.length!=0) {
for(File f:fs) {
delDir(f.getAbsolutePath());
}
}
}
file.delete();
}else {
System.out.println("路径不存在!");
}
}
I/O流
Java中将信息的输入与输出过程抽象为I/O流(Input/Output)
- 输入:是指数据流入程序,通常我们读取外界数据时使用,所以输入是用来读取(read)数据的。
- 输出: 是指数据从程序流出,通常我们需要写出数据到外界时使用,所以输出是用来写出(write)数据的
一个流就是一个从数据源向目的地的数据序列,I/O流类一旦被创建就会自动打开通过调用close方法,可以显式关闭任何一个流,如果流对象不再被引用,Java的垃圾回收机制也会隐式地关闭。
I/O流的分类
1.按照流向分:输入流;输出流
2.按照处理数据的单位分:字节流(8位的字节);字符流(16位的字节)
3.按照流的功能分:
- 节点流(低级流):可以从一个特定的IO设备上读/写数据的流。
- 处理流(高级流/过滤流):是对一个已经存在的流的连接和封装,通过所封装的流的功能调用实现数据读/写操作。通常处理流的构造器上都会带有一个其他流的参数。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHLzkERPl3aU1UNNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL5ATN4MTMyEjM4ATMxgTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
字节流
一、字节输出流OutputStream / 字节输入流 (InputStream——抽象父类)
(1) 字节输出流(OutputStream——抽象父类)
1.write(int b) 将int类型的数据b的低八位二进制写出
如os.write(1025);1025的32位为00000000 00000000 00000100 00000001 ;则只写了一个字节 0000001
2.write(byte[] bs) 将字节数组中的所有字节写出
所以可以把1025的四个字节放入到字节数组bs中,然后.write( bs)。相当于把1025通过4次write(int b)读入
byte[] bs="1025".getBytes();
os.write(bs);
源码为:
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}
(2) 字节输入流 (InputStream——抽象父类)
1. int read() 从流中读取一个字节,存储在一个int类型数据的低八位上。
2. int read(byte[] b) 读取若干个字节,把它们保存到缓冲区b中,返回的整数表示读取的字节数,如果遇到输入流的结尾,返 回-1。
3.int available() 返回可以从输入流中读取的字节数目,可见读取存在一个指针,如果遇到输入流的结尾,返回0。
通过以下方法可以获得4个字节(若文件内字节数小于4字节则返回真实读取的字节个数):
byte[] bs = new byte[4];
int len = is.read(bs);
String info = new String(bs);
二、文件输出流 FileOutputStream / 文件输入流 FileInputStream
(1)文件输出流 FileOutputStream
1.重写模式构造器:FileOutputStream(File file)
FileOutputStream(String pathname)
2.追加模式构造器:FileOutputStream(File file,boolean append)
FileOutputStream(String pathname,boolean append)
(2)文件输入流 FileInputStream
构造器:FileInputStream(File file)
FileInputStream(String pathname)
三、字节缓冲输出流 BufferedOutputStream / 字节缓冲输如流 BufferedInputStream
(1)字节缓冲输出流 BufferedOutputStream
字节缓冲输出流内部维护了一个缓冲区(字节数组),当我们使用该流写数据时,会先写入缓冲区,当缓冲区装满时,才会一次性写出到目的地。这样,减少了写出的次数,提高了写出的效率。但是缺乏即时性,因此提供了flush()方法可以清空未满的缓冲区,强制写出。
构造器:BufferedOutputStream(OutputStream os) 此构造器内部维护了一个8k大小的缓冲区(字节数组)
其实就是调用了下面一个构造器。
public BufferedOutputStream(OutputStream out) {
this(out, 8192);
}
BufferedOutputStream(OutputStream os,int size) 此构造器可以自定义缓冲区大小
如:
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("io.txt"));
*任何输出流,在关闭操作前,都会将流内的数据写出。
public void close() throws IOException {
try {
flush();
} catch (IOException ignored) {
}
out.close();
}
*当一次性写出的字节数组的长度>=缓冲区,就不使用缓冲区而是直接写出。
public synchronized void write(byte b[], int off, int len) throws IOException {
if (len >= buf.length) {
flushBuffer();
out.write(b, off, len);
return;
}
if (len > buf.length - count) { //判断需要写出的len字节数是否大于缓冲区中的剩余空闲量
flushBuffer();
}
System.arraycopy(b, off, buf, count, len);
count += len;
}
(2)字节缓冲输如流 BufferedInputStream
同样内部维护了一个缓冲区,作用是尽可能的一次性读取更多的字节存到缓冲区,缓冲区默认大小为8k. 我们从缓冲区里读取数据,当缓冲区里的数据被读取完,缓冲区会再次存储新数据。 这样就减少了从硬盘到内存的次数。提高了读取效率。
构造器: BufferedInputStream(InputStream is)
BufferedInputStream(InputStream is,int size)
四、数据流DataOutputStream/DateInputStream
提供了一些可以直接写出/读取八大基本数据类型的方法,还提供了writeUTF(String s) / readUTF();
构造方法DataOutputStream(OutputStream os) / DataInputStream(InputStream is);
- writeInt(int v)
public final void writeInt(int v) throws IOException {
out.write((v >>> 24) & 0xFF);
out.write((v >>> 16) & 0xFF);
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
incCount(4);
}
底层调用的是OutputStream中的write(int b)方法,这个方法传递的是低八位的int;
可见writeInt(int v)不过是通过4次的移位,把int类型的4个字节分别移动到低8位(转成byte类型)上传递;
&0xFF是将8位的数据转化为32位的int类型。
writeUTF(String s)也是类似的,先判断字符占几个字节,再通过字节数决定移位次数。
五、对象流 ObjectOutputStream / ObjectInputStream
对象是存在于内存中的,有的候需要将对象保存到硬盘上,或者将对象传输到另一台计算机上的等等操作。
序列化:将对象转换成一个字节序列,WriteObject(Object o);
反序列化:将一个字节序列转换成对应的对象,readObject();
常用构造器 ObjectOutputStream(OutputStream os)
ObjectInputStream(InputStream is)
-
Serializable接口:ObjectOutputStream在进行序列化时需要对象所属的类型必须实现Serializable接口。
此接口内什么都没有,只是作为可序列化的标识。
-
serailVersionUID:实现序列化接口的类需要提供一个常量serialVersionUID,表明该类的版本。
若不显示的声明,在该对象序列化时也会根据当前类的各个方面计算该类的默认serialVersionUID。
但是不同平台的编译器实现有所不同,所以想要跨平台,都应该显示的声明版本号。
如果类的对象序列化存入硬盘上面,之后随着需求的变化更改了类的属性(增加或减少或改名等),
那么当反序列化时,就会出现InvalidClassException,造成了不兼容性的问题。
但当serialVersionUID相同时,就会将不一样的field以type的预设值反序列化,避免了不兼容问题。
- transient关键字:使用transient关键字修饰的属性在序列化时其值将被忽略。
字符流
一、字符流 Reader / Writer
Reader/Writer字符输入/输出流,都是抽象父类
字符流是以字符(char)为单位读写数据的, 一次处理一个unicode。字符流的底层仍然是基本的字节流;
字符流只能对纯文本文件进行操作。
二、转换流 OutputStreamWriter / InputStreamReader
可以设置字符集
常用构造器:OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out,String charsetName)
InputStreamReader(InputStream in)
InputStreamReader(InputStream in,String charsetName)
三、缓冲字符流 PrintWriter / BufferedReader
(1)PrintWriter 缓冲字符输出流
PrintWriter是具有自动行刷新的缓冲字符输出流,其提供了比较丰富的构造方法,通常比BufferedWriter更实用。
常用构造方法 PrintWirter(File file)
PrintWriter(String filename)
PrintWriter(OutputStream out)
PrintWriter(OutputStream out,boolean autoFlush)
PrintWriter(Writer writer)
PrintWriter(Writer writer,boolean autoFlush)
常用方法:除了write方法,PrintWriter提供了丰富的重载print()和println()方法。
println方法在输出目标数据后自动输出一个系统支持的换行符。若该流设置了自动行刷新,那么每当通过println方法 写出的内容都会被实际写出。而不是进行缓存。
(2) BufferedReader 缓冲字符输入流
常用构造器 :BufferedReader(Reader reader)
String readLine() 该方法连续读取一行字符串,直到读取到换行符位置,返回的字符串中不包含换行符。
四、文件字符流 FileWriter / FileReader
(1) FileWriter
相当于OutputStreamWriter和FileOutputStream合起来的功能。内部也维护着一个缓存区,需要手动调用flush方法进行刷新。
构造方法 FileWriter(File file)
FileWriter(File file,boolean append)
FileWriter(String filepath)
FileWriter(String filepath,boolean append)
(2) FileReader
相当于InputStreamReader和FileInputStream合起来的功能,但是不能设置字符集。内部也维护着一个缓存区。
构造方法 FileReader(File file)
FileReader(String filepath)
其他流
System.out:为PrintStream类型,代表标准输出流,默认的数据输出是控制台
out:是System类的一个静态成员变量
PrintStream ps = System.out;
System.setOut(new PrintStream("out.txt")); //更改输出目的地
System.err:为PrintStream类型,代表标准错误输出也流,默认的数据输出是控制台
System.in:为InputStream类型,代表标准输入流,默认的数据源为键盘