JAVA笔记15--文件流

檫除与转换

  1. 严格的泛型代码里,带泛型声明的类总是应该带着类型参数;
  2. 为了兼容旧的代码,也允许在使用泛型类时不指定类型实参;
  3. 若未指定类型实参,则它默认是定义泛型类时声明的类型形参的上限类型。

File

File是Java.io包下的类,代表与平台无关的文件与目录;

File能创建(createNewFile)、删除(delete)、重命名文件(renameTo)和目录,也能检测、访问文件和目录本身;

File不能访问文件的内容,如果要访问文件的内容,则需要使用输入、输出流;

路径分隔符

1.Windows系统采用反斜线(\)作为路径分隔符;

2.Java程序中可以使用两条反斜线作为路径分隔符;

3.Java也支持使用一条正斜线(/)作为路径分隔符:

过滤文件

1.File类的listFiles()方法可以接受一个参数,用于在列举文件时对其进行过滤;

2,File类会依次将文件传给过滤器,当过滤器返回true时,File类才会列举该文件。

public interface FileFilter{
    boolean accpet (File pathname);
}

public interface FilenameFilter{
    boolean accept(File dir, String name);
}

遍历文件

	public static  void printfile(String filepath,int depth) throws IllegalAccessException {
		File file=new File(filepath);
		if(!file.exists()){
			throw new IllegalAccessException("文件不存在");
		}
		for(int i=0;i>depth;i++){
			System.out.println(" ");
		}
		//打印名字
		if(file.isFile()){
			System.out.print("-");
		}
		System.out.println(file.getName());
		//目录递归
		if(file.isDirectory()){
			File[] files=file.listFiles();
			for(File f:files){
				printfile(f.getPath(),depth+1);
			}
		}

	}

IO流简介

IO(Input Output)用于实现对数据的输入与输出操作;Java把不同的输入/输出源(键盘、文件、网络等)抽象表述为流(stream);流是从起源到接收的有序数据,程序采用同一方式可以访问不同的输入、输出源。

流的分类

输入流与输出流(方向

--输入流只能读数据,不能写入数据;--输出流只能写入数据,不能读取数据。

输入、输出的方向:

通常从程序运行所在内存的角度来区分;数据从硬盘流向内存,通常称为输入流;数据从内存流向硬盘,通常称为输出流;

字节流与字符流(数据)

--字节流操作的数据单元是8位的字节;--字符流操作的数据单元是16位的字符;

节点流和处理流(功能)

--节点流可以直接从/向一个特定的IO设备(磁盘、网络等)读写数据,也称为低级流;

--处理流是对节点流的连接或封装,用于简化数据读/写功能或提高效率,也称为高级流;

流的模型

抽象基类

输入流

输出流

注意事项:

  1. 上述四个类都是抽象类,不能直接实例化;
  2. 上述四个类都定义了close()方法,你需要在使用流之后调用此方法将其关闭;
  3. 无论是否发生异常,使用流后都要阐释关闭它,通常在finally中关闭流;
  4. 上述四个类都实现了Closeable接口,因此可以在try()中创建流,以便于自动关闭。

文件流

这四个类都是节点流,会直接和指定的文件关联,即实例化时传入文件路径!

应用举例--复制文件

public static void copyfile(String filepathsrc,String filepathdest){
		try(
				FileInputStream fis=new FileInputStream(filepathsrc);
				FileOutputStream fos=new FileOutputStream(filepathdest);
				){
			byte[] bytes=new byte[128];
			int len=0;//实际读取的字节数
			while((len=fis.read(bytes,0,128))>0) {//读到末尾返回-1,结束循环
				fos.write(bytes,0,len);

			}

		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}


	public static void copytextfile(String filepath_org,String filepath_dest){
		try(
				FileReader fr=new FileReader(filepath_org);
				FileWriter fw=new FileWriter(filepath_dest);
				){
			char[] chars=new char[128];
			int len=0;
			while((len=fr.read(chars,0,128))>0){
				System.out.println(String.valueOf(chars,0,len));
				fw.write(chars,0,len);
			}

		} catch (FileNotFoundException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

缓冲流

举例:

	public static void copyfile(String scrfilepath,String destfilepath){
		try(
				BufferedInputStream bis =new BufferedInputStream(new FileInputStream(scrfilepath));
				BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(destfilepath));
//				FileInputStream fis=new FileInputStream(scrfilepath);
//				FileOutputStream fos=new FileOutputStream(destfilepath);
				){
			byte[] bytes=new byte[128];
			int len=0;
//			while((len=fis.read(bytes,0,128))>0){
//				fos.write(bytes,0,len);
//			}
			while((len=bis.read(bytes,0,128))>0){
				bos.write(bytes,0,len);
			}
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}

转换流

	public static void main(String[] args){
		try(
				InputStreamReader r=new InputStreamReader(System.in);
				BufferedReader br=new BufferedReader(r);
				)
		{
			String line=null;
			while((line=br.readLine())!=null){
				if(line.equalsIgnoreCase("exit")){
					break;
				}
				System.out.println(line);
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

打印流

重定向

在Java中:

  1. System.in代表标准输入,默认情况下代表键盘;
  2. System.out代表标准输出,默认情况下代表显示器;

实例:

RandomAccessFile

  1. RAF支持随机访问文件,即程序可以跳转到文件的任意位置来访问文件;
  2. RAF包含了丰富的功能,既支持读取文件内容,也支持文件输出数据;
  3. RAF允许自由定义文件指针,该指针既可以向前移动,也可以向后移动;
  4. RAF包含的输入和输出的方法,与InputStream和OutputStream类似;

long getFilePointer()--返回文件指针当前所指向的位置;

void seek(long pos)--将文件指针定位到指定位置(pos);

序列化

序列化机制

        序列化机制可以将对象转换成字节序列,这些字节序列可以保存在磁盘上,也可以在网络中传输,并允许程序将这些字节序列再次恢复成原来的对象。

  1. 对象的序列化(Serialize),是指将一个java对象写入IO流中;
  2. 对象的反序列化(Deserialize),是指从IO流中恢复该Java对象;

支持序列化

  1. 若对象要支持序列化机制,则它的类需要实现Serializable接口;
  2. 该接口是一个标记接口,它没有提供任何方法,只是表明该类是可以序列化的;
  3. Java的很多类已经实现了Serializable接口,如包装类,String,Date等。

实现序列化

使用对象流ObjectInputStream和ObjectOutputStream(处理流)!

  • 序列化
  1. 创建ObjectOutputStream对象;
  2. 调用ObjectOutputStream对象的writeObject()方法,以输出对象序列。
  • 反序列化
  1. 创建ObjectInputStream对象;
  2. 调用ObjectInputStream对象的readObject()方法,将对象序列恢复成对象。

序列化的规则

序列化的目的是将对象中的数据(成员变量)转换为字节序列,和成员方法无关。为了正确的序列化某个对象,这个对象以及它所对应的类需要符合如下的规则:

  1. 该对象中引用类型的成员变量必须是可序列化的;
  2. 该类的直接或间接的父类,要么具有午餐构造器,要么也是可序列化的;
  3. 一个对象只会被序列化一次,再次序列化时仅仅会输出它的序列号而已。

每个被序列化的对象都有一个序列号;在序列化对象之前,程序会先检查它是否被序列化过;若对象没有被序列化过,程序会将其转为字节序列;若对象已经被序列化过,程序会直接输出它的序列号。

序列化的版本

一个常见的场景:

        定义类的序列化版本,在反序列化时,只要对象中所存的版本和当前类的版本一致,就允许做恢复数据的操作,否则将会抛出序列化版本不一致的错误。

java允许以下形式来定义序列化版本:

prviate static final long serialVersionUID=...;(类中)

  1. 如果没有显示定义serialVersionUID,则JVM会根据类的信息自动计算出它的值;由于升级前后类的内容发生了变化,则该值的计算结果通常不同,这就会导致反序列化失败;
  2. 最好在序列化的类中显示的定义serialVersionUID,这样即便对象被序列化后,它所对应的类被修改了,由于版本号是一致的,所以该对象依然可以被正确的反序列化。
  3. 在反序列时,只有那些成功匹配上的成员变量会被恢复!

Transient关键字

transient关键字用于修饰成员变量(只能修饰成员变量,不能修饰类中其他内容),表示反序列时将会忽略它;

在某些场景中,不希望序列化某个成员变量,例如:

该成员变量是敏感信息,如用户密码、银行账号登;该成员变量是引用类型,但它没有实现序列化接口。

private transient String password;

自定义序列化

        自定义序列化,可以让程序自主控制序列化以及反序列化成员变量的方式,可以通过在类中定义如下具有特殊签名的方法进行实现。

  • 写入对象的成员变量

private void writeObject(ObjectOutputStream out) throws IOException;

  • 恢复对象的成员变量

private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException;

NIO

  1. new IO(NIO),是Java从4开始陆续增加的IO处理的新功能,这些类都被放在java.nio包以及子包下,并且Java.io包中很多类也以NIO为基础进行了改写;
  2. NIO采用内存映射文件的方式来处理输入和输出,它将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件了,这比传统的输入和输出的方式要高效很多;
  3. ChannelBuffer是NIO的两个核心对象:
    --Channel(通道)是对传统的输入/输出系统的模拟,所有数据都要通过通道传输;
    --Buffer(缓冲),是一个容器(数组),是程序与Channel沟通的桥梁,程序向Channel写入的数据都要先放到Buffer中,程序从Channel中读取的数据也会被放到Buffer中。

Buffer

Buffer是抽象类,它有如下子类:

ByteBuffer 、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer;

  • 只能通过静态方法实例化Buffer:

public static CharBuffer allocate(int capacity);

  • Buffer的核心是4个成员变量:
  1. 容量(capacity):Buffer可以存储的最大数据量,该值不可改变;
  2. 界限(limit):Buffer中可以读、写数据的边界,limit之后的数据不能访问;
  3. 位置(Position):下一个可以被读写的数据的位置(索引);
  4. 标记(Mark):Buffer允许将位置直接定位到该标记处,这是一个可选的属性;

上述变量满足如下的关系:0<=mark<=position<=limit<=capacity

示例:

Channel

Channel的实现类:

FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel、Pipe.SourceChannel、Pipe.SinkChannel;

Channel的实例化:

  1. 各个Channel类提供的open()方法;
  2. FileInputStream、FileOutputStream、RandomAcessFile类提供了getChannel()方法,可以直接返回FileChannel。

Channel方法:

  1. map()方法用于将Channel对应的数据映射成ByteBuffer;
  2. read()方法有一系列重载的形式,用于从Buffer中读取数据;
  3. write()方法有一系列重载的形式,用于向Buffer中写入数据;

Charset

  1. 编码(Encoder):将明文的字符序列转换成二进制序列;
  2. 解码(Decoder):将二进制序列转换成明文的字符序列;
  3. 字符集(Charset):字符序列与字节序列转换时所遵循的规则,若编码时采用的字符集与解码时采用的字符集不一致,就会产生乱码。

Paths、Files

  • Paths
  1. Paths类提供了两个静态的get()方法,用于返回Path类型的对象;
  2. Path是一个接口,代表与平台无关的路径,提供了访问路径的方法;
  • Files
  1. Files是一个操作文件的工具类,它提供了大量便捷的访问文件的方法。
  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值