文件与 I/O
1、装饰者模式:
动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。
2、Scanner 类
Scaner sc = new Scanner(System.in);
int n = sc.nextInt();
double m = sc.nextDouble();
String s = sc.next();
String t = sc.nextLine();
3、File 类的作用和使用方法
使用File类获取文件的各种信息;使用File类分别深度优先和广度优先遍历一个文件夹
文件的基本操作方法:
boolean exists() //文件是否已存在
boolean createNewFile() //当且仅当指定抽象路径名不存在时创建一个新的空文件
boolean delete() //删除指定抽象路径名的文件
File getAbsoluteFile() //返回抽象路径名抽象路径名形式
String getAbsolutePath() //返回抽象路径名的字符串形式
String getName() //返回抽象路径名表示的文件或路径
long length() //返回抽象路径名的文件长度
String[] list() //返回抽象路径名的文件或目录的字符串数组
File[] listFiles() //返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件
File[] listFiles(FileFilter filter) //返回Filter过滤的抽象路径名数组
boolean mkdir() //创建一个路径名为目录
boolean mkdirs() //创建多层的目录,包括不存在的目录的父目录
广度优先遍历文件夹:
// 广度优先遍历
public static void BFS(File file) {
List<File> files = new ArrayList<File>();
files.add(file);
int m = 0;
for (int i = 0; i < files.size();) {
File f = files.get(0);
if (f.isDirectory()) {
List<File> temp = Arrays.asList(f.listFiles());
files.addAll(temp);
} else {
System.out.println(f);
m++;
}
files.remove(f);
}
System.out.print(m);
}
深度优先遍历文件夹:
public static void DFS(File file) {
if (file.isDirectory()) {
List<File> temp = Arrays.asList(file.listFiles());
for (File f : temp) {
DFS(f);
}
} else {
System.out.println(file.getAbsolutePath());
}
}
4、字节流和字符流的区别
*字节流:基本的处理单元是每个字节,通常用来处理任何二进制数据(字节或字节数组);默认不使用缓冲区;InputStream, OutputStream*字符流:基本的处理单元是Unicode码元,通常用来处理文本数据(字符、字符数组或字符串)。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好;使用缓冲区;Reader, Writer
操作流程
在Java中IO操作也是有相应步骤的,以文件操作为例,主要的操作流程如下:
1) 使用File类打开一个文件
2) 通过字节流或字符流的子类,指定输出的位置
3) 进行读/写操作
4)关闭输入/输出
IO 操作属于资源操作,一定要记得关闭
5、复制文件
*使用 FileInputStream 和 FileOutputStream 复制文件
public static void copyFileByFileStream(File source, File dest, int bufferSize) throws IOException {
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(source);
out = new FileOutputStream(dest);
byte[] buf = new byte[bufferSize];
int copySize;
while ((copySize = in.read(buf)) > 0)
out.write(buf, 0, copySize);
} finally {
in.close();
out.close();
}
}
*使用 BufferedInputStream 和 BufferedOutputStream 复制文件
public static void copyFileByBufferedStream(File source, File dest, int bufferSize) throws IOException {
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(new FileInputStream(source));
out = new BufferedOutputStream(new FileOutputStream(dest));
byte[] buf = new byte[bufferSize];
int copySize;
while ((copySize = in.read(buf)) > 0)
out.write(buf, 0, copySize);
} finally {
in.close();
out.close();
}
}
*对比效率
BufferedInputStream 比 FileInputStream 多了一个缓冲区,执行read时先从缓冲区读取,当缓冲区数据读完时再把缓冲区填满。因此,当每次读取的数据量很小时,FileInputStream 每次都是从硬盘读入,而BufferedInputStream大部分是从缓冲区读入。读取内存速度比读取硬盘的速度快得多,因此 BufferedInputStream 效率高。 BufferedInputStream 的默认缓冲区大小是8192字节。每当读取数量接近或远超这个值时,两者的效率就没有明显的差别了。BufferedOutputStream 和 FileOutputStream 同理,差异更明显一些。
*使用FileChannel复制文件
public static void fileChannelCopy(File s, File t) {
FileInputStream fi = null;
FileOutputStream fo = null;
FileChannel in = null;
FileChannel out = null;
try {
fi = new FileInputStream(s);
fo = new FileOutputStream(t);
in = fi.getChannel();// 得到对应的文件通道
out = fo.getChannel();// 得到对应的文件通道
in.transferTo(0, in.size(), out);// 连接两个通道,并且从in通道读取,然后写入out通道
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fi.close();
in.close();
fo.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
6、 RandomAccessFile
完成随机读取功能,读取指定位置的内容
在文件里移动用的seek( ),以及判断文件大小的length( )、skipBytes()跳过多少字节数。此外,它的构造函数还要一个表示以只读方式("r"),还是以读写方式("rw")打开文件的参数
public static void write(File f) throws IOException {
RandomAccessFile rdf = new RandomAccessFile(f, "rw");
String name = "zhangsan";
int age = 30;
rdf.writeBytes(name);
rdf.writeInt(age);
name = "lisi ";
age = 31;
rdf.writeBytes(name);
rdf.writeInt(age);
name = "wangwu ";
age = 32;
rdf.writeBytes(name);
rdf.writeInt(age);
rdf.close();
}
public static void read(File f) throws IOException {
RandomAccessFile rdf = new RandomAccessFile(f, "r");
String name = null;
int age = 0;
byte[] b = new byte[8];
// 读取第二个人的信息
rdf.skipBytes(12);
for (int i = 0; i < b.length; i++)
b[i] = rdf.readByte();
name = new String(b);
age = rdf.readInt();
System.out.println("第二个人的信息------> 姓名:" + name + "; 年龄:" + age);
// 读取第一个人的信息
rdf.seek(0);// 指针回到文件的开头
for (int i = 0; i < b.length; i++)
b[i] = rdf.readByte();
name = new String(b);
age = rdf.readInt();
System.out.println("第一个人的信息------> 姓名:" + name + "; 年龄:" + age);
// 读取第三个人的信息
rdf.skipBytes(12);
for (int i = 0; i < b.length; i++)
b[i] = rdf.readByte();
name = new String(b);
age = rdf.readInt();
System.out.println("第三个人的信息------> 姓名:" + name + "; 年龄:" + age);
}