文章目录
1、 File 类
表示文件和目录路径名的抽象表示形式
File 类可以实现文件的创建、删除、重命名、得到路径、创建时间, 是唯一与文件本身有关的操作类
无法删除非空文件夹
路径分隔可以使用 “/” “\”
public static final String separator | 表示路径分隔符 “” |
---|---|
public File(String pathname) | 构造File 类实例, 要传入路径 |
public boolean createNewFile() | 创建新文件 |
public boolean delete() | 删除文件 |
public class FileDemo {
public static void main(String[] args) {
File fi = new File("1.txt");
System.out.println("是否存在1.txt "+ fi.exists());
if (!fi.exists()) {
try {
fi.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("是否为文件夹 "+fi.isDirectory());
System.out.println("文件大小 "+fi.length());
System.out.println("文件的绝对路径 "+fi.getAbsolutePath());
System.out.println("删除文件 "+fi.delete());
File f2 = new File("array");
File[] names = f2.listFiles();
System.out.println("array 文件夹下的文件 "+Arrays.toString(names));
File f4 = new File("temp");
f4.mkdir();
// 重命名和移动文件
f4.renameTo(new File("tempp"));
System.out.println("删除文件夹 "+new File("tempp").delete());
System.out.println("删除文件夹 "+f4.delete());
File f5 = new File("F:\\Algorithm");
// File[] files = f5.listFiles(new FileFilter() {
// @Override
// public boolean accept(File pathname) {
// return pathname.getName().endsWith(".txt");
// }
// });
File[] files = f5.listFiles((pathname)->pathname.getName().endsWith("y"));
for (File f : files) {
System.out.println("以y结尾的文件 "+f.getName());
}
}
查找文件
public class findFileDemo {
public static void main(String[] args){
findFile(new File("F:\\"),".pdf");
}
private static void findFile(File target, String ext){
if(target == null) return;
//如果文件是目录
if(target.isDirectory()){
File[] files = target.listFiles();
if(files!=null){
for(File f: files){
findFile(f,ext); // 递归调用
}
}
}else{ // 如果File 是一个文件
String name = target.getName().toLowerCase();
if(name.endsWith(ext)){
System.out.println(target.getAbsolutePath());
}
}
}
}
2、 字节流
以字节为单位
流是一组有顺序的,有起点和重点的字节集合,是对数据传输的总称或抽象,即数据在两设备间的传输称为流
流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作
根据处理数据类型的不同分为:字符流和字节流。 根据数据流向不同分为:输入流和输出流
public abstrat class OutputStream extends Object implements Closeable, Flushable
public abstract vlass InputStream extends Object implements Closeable
输出流:超类OutputStream, 对文件的输出流使用子类FileOutputStream
输入流 超类InputStream, 对文件的输入流使用子类FileOutputStream
原理:
每次只会操作一个字符,(从我呢见中读取或写入)
public class ByteStreamDemo {
private static void out() throws IOException {
File file = new File("1.txt");
file.createNewFile();
OutputStream out = new FileOutputStream(file, true); // append 为true 表示追加内容
String info = "hahalal辣豆腐\r\n";
String line = System.getProperty("line.separator");
info += line;
out.write(info.getBytes());
out.close();
}
private static void in() throws IOException {
File file = new File("1.txt");
InputStream in = new FileInputStream(file);
byte[] bytes = new byte[1024]; // 每次读取的字节长度,1兆
StringBuilder buf = new StringBuilder();
int len = -1; // 把数据读到数组中,并返回读取的字节数,当不等-1时,表示读取到数据,等于-1表示文件已经读完了
while ((len = in.read(bytes)) != -1) {
buf.append(new String(bytes,0,len));
}
in.close();
System.out.println(buf);
file.delete();
}
public static void main(String[] args) throws IOException {
out();
in();
}
}
3、字符流
以字符为单位
writer
写入字符流的抽象类。子类必须实现的方法仅有write(char[], int, int)\ flush() 和 close() 但是多数子类将重写此处定义的一些方法,以提供更高的效率或其他功能
与OutputStream 一样,对文件的操作使用: FileWriter 类完成
Reader
用于读取字符流的抽象类,子类必须实现的方法只有read(char[]. int, int) 和close() , 但是大多数子类将重写此处定义的一些方法,以提供更高的效率或其他功能, 使用FileReader 类进行实例化操作
public class CharStreamDemo {
// 文件字符操作流会自带缓存,默认大小为1024,在缓存满后,或手动刷新缓存,或关闭流会把数据写入文件
private static void out() throws IOException {
File file = new File("1.txt");
Writer out = new FileWriter(file,true);
out.write("村花到我家\n");
out.close();// 有一个writeBuffer 数组,缓存超过1KB 或者close 后才会写入到文件中
}
public static void in() throws IOException {
File file = new File("1.txt");
Reader in = new FileReader(file);
char[] cs = new char[1];
int len = -1;
StringBuilder buf = new StringBuilder();
while((len = in.read(cs))!= -1){
buf.append(new String(cs,0,len));
}
in.close();
System.out.println(buf);
}
public static void main(String[] args) throws IOException {
out();
in();
}
}
字节流与字符流的区别
在所有的流操作里,字节永远是最基础的。任何基于字节的操作都是正确的,无论你是文本文件还是二进制的文件。如果确认流里面只有可打印的字符,包括英文的和各种国家的汉字,也包括中文,那么可以考虑使用字符流。由于编码不同,多字节的字符可能占用多个字节。比如GBK的汉字就占用2个字节,而UTF-8的汉字就占用3个字节。所以,字符流是根据指定的编码,将1个或多个字节转化为java里面的unicode 字符,然后进行操作,字符操作一般使用Writer , Reader, 字节操作一般是InputStream, OutputStream, 以及各种包装类, 如BufferedInputStream 和 BufferedOutputStream
总结: 如果要处理的流是可以印的字符,那么使用字符流更简单一点,如果不确定使用字节流不会出错
复制文件
public class CopyFileDemo {
public static void main(String[] args) {
System.out.println("start");
long start = System.currentTimeMillis();
copy("F:\\千峰java\\千锋java基础教程:第08章 文件与IO\\第08章 文件与IO_01_File类的使用.mp4", "F:\\第08章 文件与IO_01_File类的使用.mp4");
System.out.println("end");
long end = System.currentTimeMillis();
System.out.println(end - start);
}
private static void copy(String src, String target) {
File srcFile = new File(src);
File targetFile = new File(target);
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(srcFile);
out = new FileOutputStream(targetFile);
byte[] bytes = new byte[1024];
int len = -1;
while ((len = in.read(bytes)) != -1) {
out.write(bytes, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null) in.close();
if (out != null) out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4、 字节字符转换流
可以将一个字节流转换为字符流,也可以将一个字符流转换为字节流
字节流:FileOutputStream FileInputStream 字符流: FileWriter FileReader
OutputStreamWriter: 将输出的字符流转化为字节流的输出形式
InputStreamReader: 将输入的字节流转换为字符流输入形式
输入: 文件 —> InputStream —> InputStreamReader —> 程序
输出: 文件 <— OutputStream <— OutputStreamWriter <— 程序
public class ChangeStreamDemo {
// 读入到程序,将字节流转换为字符流,操作更方便
private static void read(InputStream in){
Reader reader = new InputStreamReader(in, Charset.forName("utf-8"));
char[] cs = new char[1024];
int len = -1;
try {
while ((len = reader.read(cs)) != -1) {
System.out.println(new String(cs, 0, len));
}
reader.close();
}catch(Exception e ){
e.printStackTrace();
}
}
// 输出到文件, 将字符流变为字节流
public static void write(OutputStream out) throws IOException {
Writer writer = new OutputStreamWriter(out, Charset.defaultCharset());
writer.write("开开心心来玩耍");
}
public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream("1.txt");
read(in);
OutputStream out = new FileOutputStream("1.txt");
write(out);
}
}
5、 缓冲流
对文件或其他目标频繁的读写操作,效率低,性能差
使用缓冲流的好处是:能够更高效的读写信息,原理是将数据先缓存起来,然后一起写入或者读取出来
BufferedInputStream: 为另一个输入流添加一些功能,在创建BufferedInputStream 时, 会创建一个内部缓冲区数组,用于缓冲数据
最大的缓存大小是Integer.MAX_VALUE - 8
BufferedOutputStream: 通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统
内部默认的缓存大小是8KB, 每次写入时缓存到缓存中的byte数组中,当数组存满时,会把数组中的数据写入文件,并把缓存下标归零
BufferedReader: 从字符输入流中读取文本, 缓冲各个字符,从而实现字符、数组和行的高效读取
BufferedWriter : 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入
public class BufferStreamDemo {
private static void byteWriter() throws IOException { // 缓存 8KB
File file = new File("1.txt");
OutputStream out = new FileOutputStream(file,true);
BufferedOutputStream bos = new BufferedOutputStream(out);
bos.write("你好呀\n".getBytes());
bos.close(); // flush 方法就是刷新用的
}
private static void byteReader() throws IOException { // 缓存很大
File file = new File("1.txt");
InputStream in = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(in);
byte[] bytes = new byte[1024];
int len = -1;
while((len = bis.read(bytes))!= -1){
System.out.println(new String(bytes,0,len));
}
bis.close();
}
public static void main(String[] args) throws IOException {
byteWriter();
System.out.println();
byteReader();
}
}
字符流
- 加入字符缓冲流,增强读取功能(readLine)
- 更高效的读取数据
FileReader: 内部使用InputStreamReader (sub.nio.cs.StreamDecoder), 解码过程, byte —> char, 默认缓存大小是8K
BufferedReader: 默认缓存大小是8K, 但可以手动指定缓冲大小,把数据读取到缓存中, 减少每次转换过程,效率更高
BufferedWriter: 同上
6、 打印流
更方便的进行输出, 再字节输出时,可以泽强输出功能
字节打印流: PrintStream
字符打印流: printWriter
public class PrintStreamDemo {
private static void charPrint() throws IOException {
File file = new File("2.txt");
Writer out = new FileWriter(file);
// 加缓存
BufferedWriter bos = new BufferedWriter(out);
// 增强打印功能
PrintWriter ps = new PrintWriter(bos);
ps.println("打印");
ps.close();
}
private static void bytePrint() throws FileNotFoundException {
File file = new File("2.txt");
OutputStream out = new FileOutputStream(file);
// 加缓存
BufferedOutputStream bos = new BufferedOutputStream(out);
// 增强打印功能
PrintStream ps = new PrintStream(bos);
ps.println("打印");
ps.close();
}
public static void main(String[] args) throws FileNotFoundException {
bytePrint();
}
}
7、 对象流
对象流的两个类:
ObjectOutputStream 将Java 对象的基本数据类型和图形写入OutputStream
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化
什么时候需要序列化
- 把对象存储在物理介质上
- 对象需要在网络上传输
序列化一组对象
如果一个类需要被序列化,那么该类必须实现Serializable 接口, 是一个标记接口,没有任何定义,只是为了告诉Jvm 该类对象可以被序列化。
在序列化操作中,同时序列化多个对象时,反序列化也必须按顺序操作,如果想要序列化一组对象:
序列化一组对象可采取:对象数组的形式,因为对象数组可以向Object进行转型操作。
transient 关键字:
如果用transient 声明一个实例变量: 当对象存储时,它的值不需要维持,所声明的字段无法序列化(被忽略掉)
public class ObjectStreamDemo {
public static void writeObject() throws IOException {
Dog dog = new Dog("大王");
File file = new File("dog.obj");
OutputStream out = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(dog);
}
public static void readObject() throws IOException, ClassNotFoundException {
File file = new File("dog.obj");
InputStream in = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(in);
Dog dog = (Dog) ois.readObject();
ois.close();
System.out.println(dog);
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
writeObject();
readObject();
}
}
我们直到在Java中,对象的序列化可以通过实现两种接口来实现,若实现的是Serializable 接口,则所有的序列化将会自动进行,若实现的是Externalizable 接口,则没有任何东西可以自动序列化,需要在writeExternal 方法中进行手工指定所要序列化的变量,这与是否被transient修饰无关,
8、 字节数组流
ByteArrayInputStream
包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪read方法要提供的下一个字节。关闭ByteArrayInputStream 无效,此类方法在关闭流后仍可被调用,而不会产生任何IOException
ByteArrayOutputStream
此类实现了一个输出流,其中的数据被写入一个byte 数组。 缓冲区随着数据不断写入而自动增长。可使用toByteArray() 和 toString() 获取数据。 关闭ByteArrayOutputStream 无效, 此类方法在关闭此流后仍可被调用,而不会产生任何IOException
// 内部维护着一个字节数组,可以利用流的读取机制来处理字符串
// 基于内存的, 不需要关闭, 和文件也没有关系
public class ByteArrayStreamDemo {
private static void byteArray(){
String s = "12345667890;'./dDF";
ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int curr = -1; // 每次读取的字节
while((curr = bais.read()) != -1){
if((curr >=65 && curr <= 90) || (curr >= 97 && curr <= 122)){
baos.write(curr);
}
}
System.out.println(baos.toString());
}
public static void main(String [] args){
byteArray();
}
}