File类

构造方法 :

  • File(String pathname):根据一个路径得到File对象
  • File(String parent, String child):根据一个目录和一个子文件/目录得到File对象
  • File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象

判断方法 :

  • public boolean isDirectory():判断是否是目录
  • public boolean isFile():判断是否是文件
  • public boolean exists():判断是否存在
  • public boolean canRead():判断是否可读
  • public boolean canWrite():判断是否可写
  • public boolean isHidden():判断是否隐藏

获取方法 :

  • public String getAbsolutePath():获取绝对路径
  • public String getPath():获取路径
  • public String getName():获取名称
  • public long length():获取长度。字节数
  • public long lastModified():获取最后一次的修改时间,毫秒值
  • public String[] list():获取指定目录下的所有文件或者文件夹的名称数组
  • public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组

创建方法 :

  • public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了
  • public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了
  • public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来

文件名称过滤器方法:

  • public String[] list(FilenameFilter filter):返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。
  • public File[] listFiles(FileFilter filter):返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.io.File;
import java.io.FilenameFilter;

public class Testing3 {
public static void main(String[] args) {
File dir = new File("F:/乱七八糟/360安全浏览器下载/chrome/下载/messing/小说");

String[] arr = dir.list(new FilenameFilter(){

@Override
public boolean accept(File dir, String name) {
File f = new File(dir,name);
return f.isFile() && f.getName().endsWith(".epub");
}
});

for (String s :arr){
System.out.println(s);
}
}
}

/*
[岬+鹭宫]三角距离无限为零.epub
为了女儿击倒魔王.epub
在异世界迷宫开后宫.epub
赌博师不会祈祷.epub
*/

重命名和删除方法 :

  • public boolean renameTo(File dest):把文件重命名为指定的文件路径
  • public boolean delete():删除文件或者文件夹

重命名注意事项

1
2
3
4
File file1 = new File("xxx.txt");
File file2 = new File("ooo.txt");

file1.renameTo(file2);
  • 如果路径名相同,就是改名。
  • 如果路径名不同,就是将文件剪切到指定位置并改名

删除注意事项:

  • Java中的删除不走回收站。
  • 要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹。

IO流

  • 字节流的抽象父类:
    • InputStream
    • OutputStream
  • 字符流的抽象父类:
    • Reader
    • Writer

FileInputStream

FileInputStream.read()方法就只会读取一个字节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Demo1_FileInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("xxx.txt"); //创建流对象
int x = fis.read(); //从硬盘上读取一个字节
System.out.println(x);
int y = fis.read();
System.out.println(y);
int z = fis.read();
System.out.println(z); // 当读取到最后的时候返回-1
fis.close(); //关流释放资源
}
}

所以得出一般的读取文件的操作方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Demo1_FileInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("xxx.txt"); //创建流对象
int b;
while((b = fis.read()) != -1) {
System.out.println(b);
}
fis.close();
}
}

read()方法读取的是一个字节,为什么返回是int,而不是byte

  • 因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,
  • 如果每次读取都返回byte,有可能在读到中间的时候遇到111111111,那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,
  • 所以在读取的时候用int类型接收,如果11111111会在其前面补上24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型

FileOutputStream

write()一次写出一个字节

FileOutputStream在创建对象的时候是如果没有这个文件会帮我创建出来,如果有这个文件就会先将文件清空,如果想追加 , 就添加一个true参数:

1
FileOutputStream fos = new FileOutputStream("yyy.txt",true);
1
2
3
4
5
6
7
8
9
public class Demo2_FileOutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("yyy.txt"); //创建字节输出流对象,如果没有就自动创建一个
fos.write(97); //虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前三个8位
fos.write(98);
fos.write(99);
fos.close();
}
}

方法 :

1
FileOutputStream fos = new FileOutputStream("yyy.txt"); 
  • fos.available() : 文件的剩余字节数
  • fis.read(arr) / fos.write(arr)
1
2
3
byte[] arr = new byte[fis.available()];   //创建与文件一样大小的字节数组
fis.read(arr); //将文件上的字节读取到内存中
fos.write(arr); //将字节数组中的字节数据写到文件上

实际上不推荐上面的做法 , 因为有可能会导致内存溢出

最好的读取写入方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("致青春.mp3");
FileOutputStream fos = new FileOutputStream("copy.mp3");

byte[] arr = new byte[1024 * 8];
int len;
//len = fis.read(arr)如果忘记加arr,返回的就不是读取的字节个数,而是字节的码表值
while((len = fis.read(arr)) != -1) {
fos.write(arr,0,len);
}

fis.close();
fos.close();
}

fos.write(b,offset,len) :

  • b : 数据
  • offset : 数据中的起始偏移量
  • len : 要写入的字节数

BufferedInputStream 和 BufferedOutputStream

字节缓冲区流

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("致青春.mp3"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.mp3"));

int b;
while((b = bis.read()) != -1) {
bos.write(b);
}
// 只需干掉包装流,原始流自动关闭
bis.close();
bos.close();
}
  • BufferedInputStream
    • BufferedInputStream内置了一个缓冲区(数组)
    • 从BufferedInputStream中读取一个字节时
    • BufferedInputStream会一次性从文件中读取8192个, 存在缓冲区中, 返回给程序一个
    • 程序再次读取时, 就不用找文件了, 直接从缓冲区中获取
    • 直到缓冲区中所有的都被使用过, 才重新从文件中读取8192个
  • BufferedOutputStream
    • BufferedOutputStream也内置了一个缓冲区(数组)
    • 程序向流中写出字节时, 不会直接写到文件, 先写到缓冲区中
    • 直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里

带缓冲区的拷贝

内存的运算效率比硬盘要高的多,所以只要降低硬盘的读写次数就会提高效率

小数组的读写和带Buffered的读取哪个更快?

  • 定义小数组如果是8192个字节大小和Buffered比较的话定义小数组会略胜一筹,
  • 因为读和写操作的是同一个数组 , 而Buffered操作的是两个数组

close()的作用

  • 一定要手动调用close()方法
  • 原因:
    1. 节省资源
    2. close()会自动调用flush().防止因为缓冲区导致拷贝不完全.

字节流读写中文

  • 字节流读取中文的问题 : 字节流在读中文的时候有可能会读到半个中文,造成乱码

  • 字节流写出中文的问题

    • 字节流直接操作的字节,所以写出中文必须将字符串转换成字节数组
    • 写出回车换行 write(“\r\n”.getBytes());
    1
    2
    3
    4
    5
    6
    public static void main(String[] args) throws IOException {
    FileOutputStream fos = new FileOutputStream("zzz.txt");
    fos.write("我读书少,你不要骗我".getBytes());
    fos.write("\r\n".getBytes());
    fos.close();
    }

文件异常处理的标准方式

JDK1.6版本及之前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static void demo1() throws FileNotFoundException, IOException {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("xxx.txt");
fos = new FileOutputStream("yyy.txt");

int b;
while((b = fis.read()) != -1) {
fos.write(b);
}
}finally {
try{
if(fis != null)
fis.close();
}finally { //try fianlly的嵌套目的是能关一个尽量关一个
if(fos != null)
fos.close();
}
}
}

JDK1.7版本及以后

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) throws IOException {
try(
FileInputStream fis = new FileInputStream("xxx.txt");
FileOutputStream fos = new FileOutputStream("yyy.txt");
){
int b;
while((b = fis.read()) != -1) {
fos.write(b);
}
}
}

类似于python的with语句

  1. try()括号里面的定义变量,在执行完{}里面的语句后会自动调用关闭方法

  2. python与java的对比:

    1
    2
    3
    # 语句A的返回值就是变量B
    with 语句A as 变量B:
    语句C
    1
    2
    3
    4
    5
    try(
    变量B = 语句A;
    ){
    语句C;
    }

FileReader 和 FileWriter

1
2
3
4
5
6
7
8
9
10
11
12
public class Demo1_FileReader {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("xxx.txt");
int c;

while((c = fr.read()) != -1) { //通过项目默认的码表一次读取一个字符
System.out.print((char)c);
}

fr.close();
}
}
1
2
3
4
5
6
7
8
9
public class Demo2_FileWriter {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("yyy.txt");
fw.write("大家好!!!");
fw.write(97);
// 一定要钓友close()
fw.close();
}
}

注意

  • FileWriter自带一个大小为2k的缓冲区
  • 所以一定要调用fw.close();来flush

Write方法的重载

  • public void write(int c) throws IOException : 往FileWriter写入单个字符c。
  • public void write(char [] c, int offset, int len) : 写入字符数组中开始为offset长度为len的某一部分。
  • public void write(String s, int offset, int len) : 写入字符串中开始为offset长度为len的某一部分。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Demo3_Copy {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("xxx.txt");
FileWriter fw = new FileWriter("yyy.txt");

char[] arr = new char[1024];
int len;
while((len = fr.read(arr)) != -1) { //将文件上的数据读取到字符数组中
fw.write(arr,0,len); //将字符数组中的数据写到文件上
}

fr.close();
fw.close();
}
}

什么情况下使用字符流

  • 程序需要拷贝一段文本, 不推荐使用字符流. 因为读取时会把字节转为字符, 写出时还要把字符转回字节.
  • 程序需要读取一段文本, 或者需要写出一段文本的时候可以使用字符流
  • 读取的时候是按照字符的大小读取的,不会出现半个中文
  • 写出的时候可以直接将字符串写出,不用转换为字节数组

注意:

  • 字符流不可以拷贝非纯文本的文件
  • 因为在读的时候会将字节转换为字符,在转换过程中,可能找不到对应的字符,就会用?代替,写出的时候会将字符转换成字节写出去
  • 如果是?,直接写出,这样写出之后的文件就乱了,看不了了

InputStreamReader 和 OutputStreamWriter

修改编码表

FileReader / FileWriter是使用默认码表读取/写入文件, 如果需要使用指定码表读取/写入, 那么可以使用InputStreamReader(字节流,编码表)OutputStreamWriter(字节流,编码表)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Demo7_TransIO {
public static void main(String[] args) throws FileNotFoundException, IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("utf-8.txt"), "uTf-8"); //指定码表读字符
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"), "gbk"); //指定码表写字符

int c;
while((c = isr.read()) != -1) {
osw.write(c);
}

isr.close();
osw.close();
}
}

或者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Demo7_TransIO {
public static void main(String[] args) throws IOException {
BufferedReader br = //更高效的读
new BufferedReader(new InputStreamReader(new FileInputStream("utf-8.txt"), "utf-8"));
BufferedWriter bw = //更高效的写
new BufferedWriter(new OutputStreamWriter(new FileOutputStream("gbk.txt"), "gbk"));
int c;
while((c = br.read()) != -1) {
bw.write(c);
}

br.close();
bw.close();
}
}

转换流

BufferedReader 和 BufferedWriter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Demo3_Copy {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("xxx.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("yyy.txt"));

int c;
while((c = br.read()) != -1) {
bw.write(c);
}

br.close();
bw.close();
}
}

BufferedReader.readLine() 和 BufferedWriter.newLine()

  • BufferedReader的readLine()方法可以读取一行字符(不包含换行符号)
  • BufferedWriter的newLine()可以输出一个跨平台的换行符号”\r\n”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Demo4_Buffered {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("aaa.txt"));

String line;
while((line = br.readLine()) != null) {
bw.write(line);
bw.newLine(); //写出回车换行符
}

br.close();
bw.close();
}
}

将一个文本文档上的文本反转,第一行和倒数第一行交换,第二行和倒数第二行交换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

public class Testing {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("aaa.txt"));

ArrayList<String> list = new ArrayList<>();

String line;
while((line = br.readLine()) != null) {
list.add(line);
bw.newLine();
}

for (int i= list.size()-1; i>=0; i--) {
bw.write(list.get(i));
bw.newLine();
}

br.close();
bw.close();
}
}

LineNumberReader

LineNumberReader是BufferedReader的子类, 具有相同的功能, 并且可以统计行号

  • 调用getLineNumber()方法可以获取当前行号
  • 调用setLineNumber()方法可以设置当前行号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

public class Demo5_LineNumberReader {
public static void main(String[] args) throws IOException {
LineNumberReader lnr = new LineNumberReader(new FileReader("zzz.txt"));

String line;
lnr.setLineNumber(100);
while((line = lnr.readLine()) != null) {
System.out.println(lnr.getLineNumber() + ":" + line);
}

lnr.close();
}
}

SequenceInputStream

什么是序列流

  • 序列流可以把多个字节输入流整合成一个,
  • 从序列流中读取数据时, 将从被整合的第一个流开始读, 读完一个之后继续读第二个, 以此类推.

不使用序列流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Demo01_SequenceInputStream {
// 将a.txt和b.txt写到c.txt
public static void main(String[] args) throws FileNotFoundException, IOException {
FileInputStream fis1 = new FileInputStream("a.txt"); //创建字节输入流关联a.txt
FileOutputStream fos = new FileOutputStream("c.txt"); //创建字节输出流关联c.txt

int b1;
while((b1 = fis1.read()) != -1) { //不断的在a.txt上读取字节
fos.write(b1); //将读到的字节写到c.txt上
}
fis1.close(); //关闭字节输入流

FileInputStream fis2 = new FileInputStream("b.txt");
int b2;
while((b2 = fis2.read()) != -1) {
fos.write(b2);
}

fis2.close();
fos.close();
}
}

使用方式:整合两个: SequenceInputStream(InputStream, InputStream)

1
2
3
4
FileInputStream fis1 = new FileInputStream("a.txt");//创建输入流对象,关联a.txt
FileInputStream fis2 = new FileInputStream("b.txt");//创建输入流对象,关联b.txt
SequenceInputStream sis = new SequenceInputStream(fis1, fis2);//将两个流整合成一个流
FileOutputStream fos = new FileOutputStream("c.txt");//创建输出流对象,关联c.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Demo01_SequenceInputStream {
public static void main(String[] args) throws FileNotFoundException,IOException {
FileInputStream fis1 = new FileInputStream("a.txt");
FileInputStream fis2 = new FileInputStream("b.txt");

SequenceInputStream sis = new SequenceInputStream(fis1, fis2);
FileOutputStream fos = new FileOutputStream("c.txt");

int b;
while((b = sis.read()) != -1) { // 读取序列流
fos.write(b);
}

sis.close(); //sis在关闭的时候,会将构造方法中传入的流对象也都关闭
fos.close();
}
}

注意 : SequenceInputStream(InputStream, InputStream)已经限死了两个参数 ,如果要合并多个流 , 就要使用SequenceInputStream(Enumeration<? extends InputStream> e)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Demo01_SequenceInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis1 = new FileInputStream("a.txt");
FileInputStream fis2 = new FileInputStream("b.txt");
FileInputStream fis3 = new FileInputStream("c.txt");

Vector<FileInputStream> v = new Vector<>(); //创建集合对象
v.add(fis1); //将流对象存储进来
v.add(fis2);
v.add(fis3);

Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en); //将枚举中的输入流整合成一个
FileOutputStream fos = new FileOutputStream("d.txt");

int b;
while((b = sis.read()) != -1) {
fos.write(b);
}

sis.close();
fos.close();
}
}

ByteArrayOutputStream

什么是内存输出流 : 该输出流可以向内存中写数据, 把内存当作一个缓冲区, 写出之后可以一次性获取出所有数据

此类实现了一个输出流,其中的数据被写入一个 byte数组。缓冲区会随着数据的不断写入而自动增长。可使用toByteArray()和toString()获取数据。

使用方式

  • 创建对象: new ByteArrayOutputStream()
  • 写出数据: write(int), write(byte[])
  • 获取数据: toByteArray()

因为ByteArrayOutputStream对接的是内存 , 内存用完直接就释放了 , 没有对接硬盘 .所以ByteArrayOutputStream不需要关闭.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Demo02_ByteArrayOutputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("e.txt");
ByteArrayOutputStream baos = new ByteArrayOutputStream(); //在内存中创建了可以增长的内存数组

int b;
while((b = fis.read()) != -1) {
baos.write(b); //将读取到的数据逐个写到内存中
}

//byte[] arr = baos.toByteArray(); //将缓冲区的数据全部获取出来,并赋值给arr数组
//System.out.println(new String(arr));

System.out.println(baos.toString()); //将缓冲区的内容转换为了字符串,在输出语句中可以省略调用toString方法
fis.close();
}
}

ObjecOutputStream

什么是对象操作流 : 该流可以将一个对象写出, 或者读取一个对象到程序中. 也就是执行了序列化和反序列化的操作.

使用方式

  • 写出: new ObjectOutputStream(OutputStream), writeObject()
  • 读取: new ObjectInputStream(InputStream), readObject()
1
2
3
4
5
6
7
8
9
10
11
12
13
// 写
public class Demo03_ObjectOutputStream {
public static void main(String[] args) throws IOException, FileNotFoundException {
Person p1 = new Person("张三", 23);
Person p2 = new Person("李四", 24);

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e.txt"));
oos.writeObject(p1);
oos.writeObject(p2);

oos.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 读
public class Demo04_ObjectInputStream {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e.txt"));

Person p1 = (Person) ois.readObject(); // 序列化的时候自动将对象转为Object类型,所以读取的时候必须强转
Person p2 = (Person) ois.readObject();
//Person p3 = (Person) ois.readObject(); //当文件读取到了末尾时出现EOFException

System.out.println(p1);
System.out.println(p2);

ois.close();
}
}

注意 : Person类必须实现Serializable接口

一次性写入/读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Demo03_ObjectOutputStream {
public static void main(String[] args) throws IOException {
Person p1 = new Person("张三", 23);
Person p2 = new Person("李四", 24);
Person p3 = new Person("王五", 25);
Person p4 = new Person("赵六", 26);

ArrayList<Person> list = new ArrayList<>();
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e.txt"));
oos.writeObject(list); //把整个集合对象一次写入
oos.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
public class Demo04_ObjectInputStream {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e.txt"));
ArrayList<Person> list = (ArrayList<Person>) ois.readObject(); //将集合对象一次读取

for (Person person : list) {
System.out.println(person);
}

ois.close();
}
}

PrintStream

  • 什么是打印流 : 该流可以很方便的将对象的toString()结果输出, 并且自动加上换行, 而且可以使用自动刷出的模式

  • System.out就是一个PrintStream, 其默认向控制台输出信息

  • System.out.println(a);

    1. 如果是Null,直接打印Null
    2. 如果不是Null,调用a.toString()方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Demo05_PrintStream {
public static void main(String[] args) throws IOException {
System.out.println("aaa");

PrintStream ps = System.out; //获取标注输出流
ps.println(97); //输出97 //底层通过Integer.toString()将97转换成字符串并打印
ps.write(97); //输出a //查找码表,找到对应的a并打印

Person p1 = new Person("张三", 23);
ps.println(p1); //默认调用p1的toString方法

Person p2 = null; //打印引用数据类型,如果是null,就打印null,如果不是null就打印对象的toString方法
ps.println(p2); // 输出null
ps.close();
}
}

修改标准输入

1
2
System.setIn(new FileInputStream("IO图片.png"));//改变标准输入流
System.setOut(new PrintStream("copy.png")); //改变标准输出流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Demo06_SystemInOut {
public static void main(String[] args) throws IOException {
//demo1();
System.setIn(new FileInputStream("a.txt")); //改变标准输入流
System.setOut(new PrintStream("b.txt")); //改变标注输出流

InputStream is = System.in; //获取标准的键盘输入流,默认指向键盘,改变后指向文件
PrintStream ps = System.out; //获取标准输出流,默认指向的是控制台,改变后就指向文件

int b;
while((b = is.read()) != -1) {
ps.write(b);
}
is.close();
ps.close();
}
}

两种键盘录入

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class Demo07_SystemIn {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //InputStreamReader转换流
String line = br.readLine();
System.out.println(line);
br.close();
}
}
1
2
3
4
5
6
7
8
public class Demo07_SystemIn {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
System.out.println(line);
sc.close();
}
}

RandomAccessFile

  • 随机访问流概述
    • RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。
    • 支持对随机访问文件的读取和写入
  • read(),write(),seek()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

public class Demo08_RandomAccessFile {
public static void main(String[] args) throws IOException {
RandomAccessFile raf = new RandomAccessFile("g.txt", "rw");
raf.write(97);
int x = raf.read();
System.out.println(x);

raf.seek(0); //在指定位置设置指针
raf.write(98);
raf.close();
}
}

DataInputStream 和 DataOutputStream

什么是数据输入输出流

  • DataInputStream, DataOutputStream可以按照基本数据类型大小读写数据
  • 例如按Long大小写出一个数字, 写出时该数据占8字节. 读取的时候也可以按照Long类型读取, 一次读取8个字节.

使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
DataOutputStream(OutputStream), writeInt(), writeLong() 

public class Demo09_Data {
public static void main(String[] args) throws FileNotFoundException, IOException {
DataOutputStream dos = new DataOutputStream(new FileOutputStream("h.txt"));
dos.writeInt(997);
dos.writeInt(998);
dos.writeInt(999);
dos.close();
}
}

public class Demo09_Data {
public static void main(String[] args) throws FileNotFoundException, IOException {
DataInputStream dis = new DataInputStream(new FileInputStream("h.txt"));
int x = dis.readInt();
int y = dis.readInt();
int z = dis.readInt();

System.out.println(x);
System.out.println(y);
System.out.println(z);

dis.close();
}
}

这个流实际上用的非常的少

Properties

Properties的概述

  • Properties类是Hashtable的子类。
  • 属性列表中每个键及其对应值都是一个字符串。 Properties没有泛型。
  • Properties 类表示了一个持久的属性集
  • Properties 可保存在流中或从流中加载。
  • 经常使用Properties将配置文件读取到一个字典中

功能:

  • public Object setProperty(String key,String value)
  • public String getProperty(String key)
  • public Enumeration<String> stringPropertyNames()
  • prop.load() : 读取文件到Map中
  • prop.store : 写入到文件中
1
2
3
4
5
6
7
public class Demo10_Properties {
public static void main(String[] args) {
Properties prop = new Properties();
prop.put("abc", 123);
System.out.println(prop); // {abc=123}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.Enumeration;
import java.util.Properties;

public class Testing4 {
public static void main(String[] args) {
Properties prop = new Properties();
prop.setProperty("name", "张三");
prop.setProperty("tel", "18912345678");

System.out.println(prop); // {tel=18912345678, name=张三}

Enumeration<String> en = (Enumeration<String>) prop.propertyNames();
while(en.hasMoreElements()) {
String key = en.nextElement(); //获取Properties中的每一个键
String value = prop.getProperty(key); //根据键获取值
System.out.println(key + "="+ value);
}
}
}
/*
name=张三
tel=18912345678
*/
1
2
3
4
5
6
7
8
9
public class Demo10_Properties {
public static void main(String[] args) throws FileNotFoundException, IOException {
Properties prop = new Properties();
prop.load(new FileInputStream("config.properties")); //将文件上的键值对读取到集合中
prop.setProperty("tel", "18912345678");
prop.store(new FileOutputStream("config.properties"), null);//第二个参数是对列表参数的描述,可以给值,也可以给null
System.out.println(prop);
}
}

练习

File类递归练习(统计该文件夹大小)

从键盘接收一个文件夹路径,统计该文件夹大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.io.File;
import java.util.Scanner;

public class Test1 {
public static void main(String[] args) {
File dir = getDir();
System.out.println(getFileLength(dir));
}

public static File getDir() {
//1,创建键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个文件夹路径:");
//2,定义一个无限循环
while(true) {
//3,将键盘录入的结果存储并封装成File对象
String line = sc.nextLine();
File dir = new File(line);
//4,对File对象判断
if(!dir.exists()) {
System.out.println("您录入的文件夹路径不存在,请输入一个文件夹路径:");
}else if(dir.isFile()) {
System.out.println("您录入的是文件路径,请输入一个文件夹路径:");
}else {
//5,将文件夹路径对象返回
return dir;
}
}
}

public static long getFileLength(File dir) {
//1,定义一个求和变量
long len = 0;
//2,获取该文件夹下所有的文件和文件夹listFiles();
File[] subFiles = dir.listFiles(); //day07 Demo1_Student.class Demo1_Student.java
//3,遍历数组
for (File subFile : subFiles) {
//4,判断是文件就计算大小并累加
if(subFile.isFile()) {
len = len + subFile.length();
//5,判断是文件夹,递归调用
}else {
len = len + getFileLength(subFile);
}
}
return len;
}
}

File类递归练习(删除该文件夹)

从键盘接收一个文件夹路径,删除该文件夹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.io.File;

public class Test2 {
public static void main(String[] args) {
File dir = Test1.getDir(); //获取文件夹路径
deleteFile(dir);
}

public static void deleteFile(File dir) {
//1,获取该文件夹下的所有的文件和文件夹
File[] subFiles = dir.listFiles();
//2,遍历数组
for (File subFile : subFiles) {
//3,判断是文件直接删除
if(subFile.isFile()) {
subFile.delete();
//4,如果是文件夹,递归调用
}else {
deleteFile(subFile);
}
}
//5,循环结束后,把空文件夹删掉
dir.delete();
}
}

File类递归练习(拷贝)

从键盘接收两个文件夹路径,把其中一个文件夹中(包含内容)拷贝到另一个文件夹中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test3 {
public static void main(String[] args) throws IOException {
File src = Test1.getDir();
File dest = Test1.getDir();
if(src.equals(dest)) {
System.out.println("目标文件夹是源文件夹的子文件夹");
}else {
copy(src,dest);
}
}

public static void copy(File src, File dest) throws IOException {
//1,在目标文件夹中创建原文件夹
File newDir = new File(dest, src.getName());
newDir.mkdir();
//2,获取原文件夹中所有的文件和文件夹,存储在File数组中
File[] subFiles = src.listFiles();
//3,遍历数组
for (File subFile : subFiles) {
//4,如果是文件就用io流读写
if(subFile.isFile()) {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(subFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(newDir,subFile.getName())));

int b;
while((b = bis.read()) != -1) {
bos.write(b);
}

bis.close();
bos.close();
//5,如果是文件夹就递归调用
}else {
copy(subFile,newDir);
}
}
}
}

File类递归练习(按层级打印)

从键盘接收一个文件夹路径,把文件夹中的所有文件以及文件夹的名字按层级打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.io.File;

public class Test4 {
public static void main(String[] args) {
File dir = Test1.getDir(); //获取文件夹路径
printLev(dir,0);
}

public static void printLev(File dir,int lev) {
//1,把文件夹中的所有文件以及文件夹的名字按层级打印
File[] subFiles = dir.listFiles();
//2,遍历数组
for (File subFile : subFiles) {
for(int i = 0; i <= lev; i++) {
System.out.print("\t");
}
//3,无论是文件还是文件夹,都需要直接打印
System.out.println(subFile);
//4,如果是文件夹,递归调用
if(subFile.isDirectory()) {
//printLev(subFile,lev + 1);
printLev(subFile,++lev);
}
}
}
}

斐波那契数列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Test5 {
public static void main(String[] args) {
System.out.println(fun(8));
}

public static void demo1() {
//用数组做兔
int[] arr = new int[8];
//数组中第一个元素和第二个元素都为1
arr[0] = 1;
arr[1] = 1;
//遍历数组对其他元素赋值
for(int i = 2; i < arr.length; i++) {
arr[i] = arr[i - 2] + arr[i - 1];
}
//如何获取最后一个数
System.out.println(arr[arr.length - 1]);
}

public static int fun(int num) {
if(num == 1 || num == 2) {
return 1;
}else {
return fun(num - 2) + fun(num - 1);
}
}
}