java入门-文件与IO流

File类

提供一些方法(api)来操纵文件和获取文件的信息

File常用API

属性

获取系统分隔符

不同操作系统的分隔符

windows的目录分割符号是用向右的斜线,java中\ 表示转义字符,所以向右的斜线需要写两个 \;

linux目录分割符号是向左的斜线: /

private static final FileSystem fs = DefaultFileSystem.getFileSystem();
public static final char separatorChar = fs.getSeparator();
public static final String pathSeparator = "" + pathSeparatorChar; 

程序案例:

System.out.println("File.pathSeparator:" + File.pathSeparator);
System.out.println("File.separatorChar:" + File.separatorChar);

程序运行结果:

File.pathSeparator:;
File.separatorChar:\

方法

获取文件/文件夹名称

程序案例:

File file = new File("D:\\java-workspace");
System.out.println("文件夹/文件名: " + file.getName());
System.out.println("绝对路径:" + file.getAbsolutePath());
System.out.println("路径: " + file.getPath());

程序运行结果:

文件夹/文件名: \java-workspace
绝对路径:D:\\java-workspace
路径: D:\\java-workspace
文件夹/文件

程序案例:

File file = new File("D:\\java-workspace");
System.out\.println("是否是文件: " + file.isDirectory());
System.out\.println("是否是文件: " + file.isFile());

程序运行结果:

是否是文件: true
是否是文件: false 
文件操作

程序案例:

File file = new File("D:\\newFile.txt");

if (file.exists()) {
	file.delete(); // 删除当前文件,如果是文件夹,要确保文件夹内容为空。
}
boolean f = file.createNewFile();

if (f) {// 如果文件创建成功
    System.out\.println("是否是隐藏问: " + file.isHidden());
    System.out\.println("最后一次修改时间: " + new Date(file.lastModified()));
    System.out\.println("是否可读: " + file.canRead());
    System.out\.println("是否可写: " + file.canWrite());
    System.out\.println("是否可执行: " + file.canExecute());
    System.out\.println("磁盘总空间大小: "+ file.getTotalSpace()/1024/1024/1024+"G");
    System.out\.println("磁盘可用空间大小: "+file.getUsableSpace()/1024/1024/1024+"G");
    System.out\.println("磁盘剩余空间大小: "+ file.getFreeSpace()/1024/1024/1024+"G");
}
修改文件名称
file.renameTo(new File("D:\\modify.txt"));	
System.out\.println("文件名称: "+ file.getName());
File nFile = new File("D:\\modify.txt");
System.out.println("修改文件名: "+ file.renameTo(nFile));

程序运行结果:

是否是隐藏问: false
最后一次修改时间: Tue Jan 25 14:28:29 CST 2022
是否可读: true
是否可写: true
是否可执行: true
磁盘总空间大小: 429G
磁盘可用空间大小: 424G
磁盘剩余空间大小: 424G
修改文件名: true
文件夹、文件访问

程序案例:

File file = new File("C:\\");
String[] fs = file.list();
File[] files = file.listFiles();

for(File f: files) {
	System.out\.println(f.getName());
}

程序运行结果(部分):

eclipse
hiberfil.sys
Intel
pagefile.sys
PerfLogs
Program Files

流的概念

流是个抽象的概念,是\对输入输出设备的抽象\,Java程序中,对于数据的输入/输出操作都是以“流”的方式进行。设备可以是文件,网络,内存等。

1.2.1 输入、输出流

提输入、输出是相对于\内存\的操作而言。

imgimg

imgimg

字节流、字符流

字节流–传输过程中,传输数据的最基本单位是字节的流。

字符流–传输过程中,传输数据的最基本单位是字符的流。

1.2.3 流的层次结构

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

imgimg

1.3 字节流

以字节为(8bits)为单位进行IO操作,一般用来处理二进制文件(例如:图片、声音、视频等)。

1.3.1 字节输入流

img

1.3.2 字节输出流

img

程序案例:

程序案例:使用字节流完成流的拷贝功能。

InputStream in = new FileInputStream("c:\\jdk-8u311-windows-x64.exe");

OutputStream out = new FileOutputStream("d:\\jdk-8u311-windows-x64.exe");

int n = 0;
long t1 = System.currentTimeMillis();

while ((n = in.read()) != -1) {
   out.write(n);

}
long t2 = System.currentTimeMillis();
out.close();
in.close();

System.out\.println("字节拷贝,耗时: " + (t2 - t1)+"ms");

程序运行结果:                                

字节拷贝,耗时: 439897ms

字节流的缓存

如果按照一个字节一个字节的进行IO操作,字节的入和出的速度不是对等的。比如我们在工地经常看到传递砖块的操作,一般不是一个砖接一个砖传递,而是几块砖头放在一起传递。在流操作中,经常用到的技术是定义一个缓存区域,积累到一定数量后,一次性发送给接收端。

img

程序案例: 使用缓存优化字节流完成流的拷贝功能

InputStream in = new FileInputStream("c:\\jdk-8u311-windows-x64.exe");

OutputStream out = new FileOutputStream("d:\\jdk-8u311-windows-x64.exe");

long t1 = System.currentTimeMillis();
byte[] buffer = new byte[1024];
while (in.read(buffer) != -1) {
  out.write(buffer);
}
long t2 = System.currentTimeMillis();
out.close();
in.close();
System.out\.println("字节缓存拷贝,耗时: " + (t2 - t1)+"ms");

程序运行结果:

字节缓存拷贝,耗时: 586ms

1.4 字符流

以字符为单位的IO操作,一般用来操作文本信息。

1.4.1 字符输入流

img

程序案例:

BufferedReader in =
new BufferedReader(
new FileReader("D:\\java-workspace\\javaio\\src\\javaio\\CopyDemo.java"));
String line = null;
int index = 0;

while ((line = in.readLine()) != null) {
	System.out\.println((++index) +"\t"+ line);

}		

in.close();

程序运行结果(部分):

1	package javaio;
2  
3	import java.io.FileInputStream;
4	import java.io.FileOutputStream;
5	import java.io.IOException;
6	import java.io.InputStream;
7	import java.io.OutputStream;

1.4.2 字符输出流

img

程序案例:

PrintWriter pw = new PrintWriter(new FileWriter("D:\\pw.html"));
pw.println("<h1>你好,java IO 流</h1>");
pw.println("<h2>java爱好者</h2>");
pw.println("<h3>测试字符输出流的用法</h3>");		
pw.flush();
pw.close();

程序运行结果:

img

流的异常捕获方案

try … catch … finally

一般流的异常都是可检查异常,所有在开发过程中需要强制使用异常捕获流程处理。一般打开流对象后,如果不关闭会一直占用一个通道(就像开辟了几条通道进行数据传输,其中一条已经完成,但是不释放则会一直占用此通道,造成资源浪费)。一般开发中我们会在finally语句块调用流的关闭语句,以此释放流资源。

程序案例:

InputStream in = null;
try{
 in = new FileInputStream(“D:\\in.dat”);
}catch(IOException e){
 //异常信息
}finally{
in.close(); //关闭流对象
}

try … with … resource

如果打开了外部资源(文件、数据库连接、网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们。因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在编程时确保在正确的时机关闭外部资源,就会导致外部资源泄露,紧接着就会出现文件被异常占用,数据库连接过多导致连接池溢出等诸多很严重的问题。

对于实现了Closeable接口的类,可以使用try…with…resource处理异常。

程序案例:

try(InputStream in = new FileInputStream(D:/abc.txt”)){
 //异常信息
}catch(IOException e){
 //捕获异常
}

序列化

序列化:一个Java对象作一下“变换”,变成\字节序列\,这样一来方便持久化存储到磁盘,避免程序运行结束后对象就从内存里消失,另外变换成字节序列也更便于网络运输和传播

反序列化:把字节序列恢复为原先的Java对象。

img

实现序列化接口的对象,有一个特殊常量serialVersinUID

img

提示: static修饰的不会被序列化,transient修饰的不会被序列化。

对象流

对象流:有的时候,我们可能需要将内存中的对象持久化到硬盘上,或者将硬盘中的对象信息读到内存中,这个时候我们需要使用对象输入输出流。

当使用对象流写入或者读取对象的时候,必须保证该对象是序列化的,这样是为了保证对象能够正确的写入文件,并能够把对象正确的读回程序。

(1) ObjectInputStream: 字节对象输入流

(2) ObjectOutputStream: 字节对象输出流

程序案例((ObjectInputStream):

public class Car implements Serializable{

	private static final long serialVersionUID\ = 1L;
	private String brand;
	private String color;
	private double price; 
	
	public Car(String brand, String color, double price) {
		this.brand = brand;
		this.color = color;
		this.price = price;
	}
  //其它代码省略
}
.....

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:\\car.dat"));
Car car = new Car("BMW", "黑色", 1200000.00);
out.writeObject(car);
out.flush();
out.close();

程序运行结果:

img

程序案例(ObjectOutputStream):

ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:\\car.dat"));
Car car = (Car) in.readObject();	
System.out\.println(car);
in.close();

程序运行结果:

Car [brand=BMW, color=黑色, price=1200000.0]

序列化接口

Serializable是一个标记性接口,没有实现任何内容,只是告诉JVM当前对象需要序列化。

public interface Serializable {

}

日志

日志概念

日志是一种记录、跟踪程序运行的技术。作用主要在以下三个方面:

调试

在Java项目调试时,查看栈信息可以方便地知道当前程序的运行状态,输出的日志便于记录程序在之前的运行结果。

错误定位

项目在运行一段时候后,可能由于数据问题,网络问题,内存问题等出现异常。这时日志可以帮助开发或者运维人员快速定位错误位置,提出解决方案。

数据分析

日志中蕴含了大量的用户数据,包括点击行为,兴趣偏好等,用户画像对于公布下一步的战略方向有一定指引作用。

日志级别

(1) ALL: 最低等级的,用于打开所有日志记录。

(2) TRACE: 很低的日志级别,一般不会使用。

(3) DEBUG: 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于打印一些调试信息。

(4) WARN: 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员一些提示。

(5) INFO: 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息。这个用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避免打印过多的日志。

(6) ERROR: 指出虽然发生错误事件,但任然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。

(7) FATAL: 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误。

log4j

Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

日志配置
Loggers

Loggers组件在此系统中被分为五个级别:DEBUG、INFO、WARN、ERROR和FATAL。这五个级别是有顺序的,DEBUG < INFO < WARN < ERROR < FATAL,分别用来指定这条日志信息的重要程度Log4j有一个规则:只输出级别不低于设定级别的日志信息,假设Loggers级别设定为INFO,则INFO、WARN、ERROR和FATAL级别的日志信息都会输出,而级别比INFO低的DEBUG则不会输出。

Appenders

禁用和使用日志请求只是Log4j的基本功能,Log4j日志系统还提供许多强大的功能,比如允许把日志输出到不同的地方,如控制台(Console)、文件(Files)等,可根据天数或者文件大小产生新的文件,可以以流的形式发送到其它地方等等。

Layouts

Log4j可以在Appenders的后面附加Layouts来完成这个功能。Layouts提供四种日志输出样式,如根据HTML样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式。

PatternLayout格式参数如下表:

序号格式含义
1%p输出日志信息的优先级:DEBUG,INFO,WARN,ERROR,FATAL。
2%d输出日志时间点的日期或时间。默认格式为ISO8601,也可以在其后指定格式。%d{yyyy/MM/dd HH:mm:ss SSS}。
3%r输出自应用程序启动到输出该log信息耗费的毫秒数。
4%t输出产生该日志事件的线程名。
5%l输出日志事件的发生位置,相当于%C%M(%F%L)的组合,包括类全名、方法、文件名以及在代码中的行数。例如:testLog4j.java:
6%c输出日志信息所属的类目,通常就是所在类的全名。
7%M输出产生日志信息的方法名
8%F输出日志消息产生时所在的文件名称
9%L输出代码中的行号
10%m输出代码中指定的具体日志位置
11%n输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”。
日志使用

配置文件: 在src定义一个properties文件: log4j.properties

配置文件案例

log4j.rootLogger = DEBUG,Console,infoFile
log4j.appender.Console = org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target = System.out
log4j.appender.Console.Threshold = DEBUG
log4j.appender.Console.layout = org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%c] - %m%n
log4j.appender.infoFile = org.apache.log4j.FileAppender
log4j.appender.infoFile.File=D:/logs/test.log
log4j.appender.infoFile.Threshold = DEBUG
log4j.appender.infoFile.layout = org.apache.log4j.PatternLayout
log4j.appender.infoFile.layout.ConversionPattern=[%c] - %m%n

程序案例:

Logger.getLogger(Logger.class).debug("测试log4j日志...");

NIO编程

java.nio全称java non-blocking IO(实际上是 new io),是指JDK 1.4 及以上版本里提供的新api(new IO) ,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络。

NIO组件

img

缓冲区

(缓冲区(Buffer): 本质上是一个可以写入数据的内存块,然后可以再次读取,该对象提供了一组方法,可以更轻松地使用内存。

img

通道(Channel):

channel(通道)可以同时进行读写,而流只能读或者只能写。

通道可以实现异步读写数据。

通道可以从缓冲读数据,也可以写数据到缓冲。

channel提供了一个map()方法,可以直接将数据映射到内存中。

img

选择器(Selector)

可以检测多个NIO channel,看看读或者写事件是否就绪。多个\Channel\以事件的方式可以注册到同一个Selector,从而达到用一个线程处理多个请求成为可能。

img

NIO编程

程序案例:

String fileName = "D:\\java-workspace\\javaio\\src\\javaio\\ReaderDemo.java";

RandomAccessFile raf = new RandomAccessFile(fileName, "rw");

/*
 * 创建Channel
 */		
FileChannel inChannel = raf.getChannel();

/*
 * 创建缓存区,缓存48个字节
 */		
ByteBuffer buffer = ByteBuffer.allocate(48);

/*
 *
 * 读取48个字符到buffer缓存中
 * 检查是否到达文件的末尾(-1表示末尾)
 */		
while((bytesRead = inChannel.read(buffer)) !=-1) {

 /*
  *
  * 把buffer当前位置更改为buffer缓冲区的第一个位置
  */

buffer.flip();		

while(buffer.hasRemaining()) {

/*
 *
 * 从buffer当前位置一个字节、一个字节的读取缓存区数据
 */

 System.out\.print((char)buffer.get());

}

/*
 *
 * 清空buffer,设置到buffer缓冲区的第一个位置
 */

buffer.clear();

}
raf.close(); 

程序运行结果(部分):

package javaio;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class ReaderDemo { 
	public static void main(String[] args) throws IOException {
        :
        :
        :

BIO/AIO/NIO概念

img

  • 10
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值