在java中,将这种通过不同输入输出设备(键盘、内存、显示器、网络等)之间的数据传输抽象表述为“流”。
I/O流主要分为3类:
本节用到的架构:
字节流:计算机所有文件(如文本、图片、视频等)都以字节形式存在,针对字节的输入输出提供了一系列的流。
InputStream的常用方法
方法声明 | 功能描述 |
---|---|
int read() | 返回从输入流读取的一个字节转化成的整数,没有则返回-1 |
int read(byte[] b) | 将读取的字节保存到字节数组b中 |
int read(byte[] b,int off,int len) | 将从位置off开始,len个字节读取的字节保存到字节数组b中 |
void close() | 关闭输入流 |
OutputStream的常用方法
方法声明 | 功能描述 |
---|---|
void write(int b) | 向输出流写入一个字节 |
void write(byte[] b) | 把字节数组b的所有字节写到输出流 |
void write(byte[] b,int off,int len) | 将字节数组b从位置off开始的len个字节写入输出流 |
void flush() | 刷新并强制写出所有缓冲的输出字节 |
void close() | 关闭输出流 |
FileInputStream类和FileOutputStream类
作用:操作文件数据
FileInputStream类实例代码
import java.io.FileInputStream;
public class Example{
public static void main(String[] args) throws Exception {
//创建一个文件字节输入流读取文件
//创建好test.txt文件,写上hello
FileInputStream in = new FileInputStream("test.txt");
int b = 0;
while((b=in.read())!=-1){
System.out.print((char)b);
}
in.close();
}
}
FileOutputStream类实例代码
import java.io.FileOutputStream;
public class Example{
public static void main(String[] args) throws Exception {
//创建文件输出流对象,并制定文件名称
//append参数:
// true:如果文件有内容,在内容后面新添内容
// false:如果文件有内容,文件数据会被清空,再写入新数据
FileOutputStream out = new FileOutputStream("out.txt", true);
String str = "hello";
out.write(str.getBytes());
out.close();
}
}
注意:为了保证I/O流的close()方法一定被执行,通常会将关闭流的操作写在finally代码块里。
finally{
try{
if(in!=null){ //如果in不为空,关闭输入流
in.close();
}
}catch(Exception e){
e.printStackTrace();
}
try{
if(out!=null){ //如果out不为空,关闭输出流
out.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
在应用程序中,I/O流通常成对出现
实例代码
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Example{
public static void main(String[] args) throws Exception {
//创建输入流对象读取文件
FileInputStream in = new FileInputStream("in.jpg");
//创建输出流对象将读取到的文件写入到指定文件中
FileOutputStream out = new FileOutputStream("dest.jpg");
int b = 0;
long startTime = System.currentTimeMillis();
while((b=in.read())!=-1){
out.write(b);
}
long endTime = System.currentTimeMillis();
System.out.println("一个耗费"+(endTime-startTime)+"毫秒。");
//一个耗费692毫秒。
in.close();
out.close();
}
}
作用:创建一个字节数组作为缓冲区,可以更快的拷贝文件
实例代码
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Example{
public static void main(String[] args) throws Exception {
//创建输入流对象读取文件
FileInputStream in = new FileInputStream("in.jpg");
//创建输出流对象将读取到的文件写入到指定文件中
FileOutputStream out = new FileOutputStream("dest.jpg");
int len = 0;
byte[] bytes = new byte[1024];
//将字节数组作为缓冲区
long startTime = System.currentTimeMillis();
while((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
}
long endTime = System.currentTimeMillis();
System.out.println("一个耗费"+(endTime-startTime)+"毫秒。");
//一个耗费1毫秒。
in.close();
out.close();
}
}
BufferedInputStream类和BuffedOutputStream类
作用:让数据的读写效率更高
构造方法的参数接收InputStream和OutputStream类型的对象
实例代码
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Example{
public static void main(String[] args) throws Exception {
//创建输入流对象读取文件
BufferedInputStream in = new BufferedInputStream(new FileInputStream("in.jpg"));
//创建输出流对象将读取到的文件写入到指定文件中
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("dest.jpg"));
int len = 0;
byte[] bytes = new byte[1024];
long startTime = System.currentTimeMillis();
while((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
}
long endTime = System.currentTimeMillis();
System.out.println("一个耗费"+(endTime-startTime)+"毫秒。");
//一个耗费0毫秒。
in.close();
out.close();
}
}
Reader类和Writer类
作用:在程序中操作字符,用法与字节流类似
FileReader类:字符输入流,从文件中读取一个或一组字符
FileWriter类:字符输出流,如果指定的文件不存在,则先创建文件,再写入数据,如果存在,则先清空文件的数据,再进行写入。
FileReader类实例代码
import java.io.FileReader;
public class Example{
public static void main(String[] args) throws Exception {
//创建FileReader对象,并指定需要读取的文件
FileReader reader = new FileReader("test.txt");
int len = 0;
while((len = reader.read())!=-1){
System.out.print((char)len);
}
reader.close();
}
}
FileWriter writerer = new FileWriter(“out.txt”,true);表示新添内容
FileWriter类实例代码
import java.io.FileWriter;
public class Example{
public static void main(String[] args) throws Exception {
//创建FileWriter对象,并指定写入数据的目标文件
FileWriter writerer = new FileWriter("out.txt");
writerer.write("床前明月光\n");
writerer.write("疑是地上霜\n");
writerer.write("举头望明月\n");
writerer.write("低头思故乡\n" );
writerer.close();
}
}
用字符流的缓冲区来进行读写操作,提高执行效率
import java.io.FileReader;
import java.io.FileWriter;
public class Example{
public static void main(String[] args) throws Exception {
FileReader reader = new FileReader("test.txt");
FileWriter writer = new FileWriter("out.txt");
long startTime = System.currentTimeMillis();
char[] chars = new char[1024];
while((reader.read(chars))!=-1){
writer.write(chars,0,chars.length);
}
long endTime = System.currentTimeMillis();
System.out.println("一共耗费"+(endTime-startTime)+"毫秒"); //1
reader.close();
writer.close();
}
}
带缓冲功能的字符缓冲流:BufferedReader类和BufferedWriter类
注意:BufferedReader类中的readLine()方法**,用于一次读取一行文本**。
实例代码
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
public class Example{
public static void main(String[] args) throws Exception {
BufferedReader reader = new BufferedReader(new FileReader("test.txt"));
BufferedWriter writer = new BufferedWriter(new FileWriter("out.txt"));
long startTime = System.currentTimeMillis();
String str = null;
while((str=reader.readLine())!=null){
writer.write(str);
writer.newLine();//换行
}
long endTime = System.currentTimeMillis();
System.out.println("一共耗费"+(endTime-startTime)+"毫秒"); //0
reader.close();
writer.close();
}
InputStreamReader类和OutputStream类
作用:将字节流转化为字符流
注意:使用转换流时,只能针对操作文本文件的字节流进行转换。
实例代码
import java.io.*;
public class Example{
public static void main(String[] args) throws Exception {
InputStreamReader reader = new InputStreamReader(new FileInputStream("test.txt"));
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("out.txt"));
BufferedReader br = new BufferedReader(reader);
BufferedWriter bw = new BufferedWriter(writer);
String str = null;
while((str = br.readLine())!=null){
bw.write(str);
bw.newLine();
}
br.close();
bw.close();
}
}
File类常用的构造方法
方法声明 | 功能描述 |
---|---|
常用:File(String path) | 通过一个path路径来创建File类对象 |
File(String parent,String child) | 根据父路径和子路径来创建File类对象 |
File(File parent,String name) | 根据File类的父路径和子路径创建File类对象 |
File类的常用方法
方法声明 | 功能描述 |
---|---|
boolean exists() | 判断File对象对应的文件或目录是否存在 |
boolean delete() | 删除File对象对应的文件或目录 |
boolean createNewFile() | 当File对象对应的文件不存在时,则新建文件 |
String getName() | 返回File对象表示的文件和文件夹的名称 |
String getpath() | 返回File对象对应的相对路径 |
String getAbsolutePath() | 返回File对象对应的绝对路径 |
String getParent() | 返回File对象对应的父路径 |
boolean canRead() | 判断File对象对应的文件或目录是否可读 |
boolean canWrite() | 判断File对象对应的文件或目录是否可写 |
boolean isFile() | 判断File对象对应的是否是文件(不是文件夹) |
boolean isDirectory() | 判断File对象对应的是否是文件夹(不是文件) |
boolean isAbsolute() | 判断File对象对应的文件或目录是否是绝对路径 |
long lastModified() | 返回1970年1月1日0时0分0秒到文件最后修改时间的毫秒值 |
long length() | 返回文件内容的长度 |
实例代码
import java.io.File;
public class Example{
public static void main(String[] args) {
File file = new File("out.txt");
System.out.println("文件名称:"+file.getName());
System.out.println("文件的相对路径::"+file.getPath());
System.out.println("文件的绝对路径::"+file.getAbsolutePath());
System.out.println("文件的父路径::"+file.getParent());
System.out.println(file.canRead()?"文件可读":"文件不可读");
System.out.println(file.canWrite()?"文件可写":"文件不可写");
System.out.println(file.isFile()?"是文件":"不是文件");
System.out.println(file.isDirectory()?"是目录":"不是目录");
System.out.println(file.isAbsolute()?"是绝对路径":"不是绝对路径");
System.out.println("文件的最后修改时间:"+file.lastModified());
System.out.println("文件的长度:"+file.length());
System.out.println("是否删除文件"+file.delete());
}
}
File类的遍历方法
方法声明 | 功能描述 |
---|---|
String[] list() | 列出文件夹里的全部文件名称 |
String[] list(函数式接口) | 通过该函数式接口可以只列出符合条件的文件 |
File[] listFiles() | 返回一个包含了File对象所有子文件和子目录的File数组 |
实例代码1
import java.io.File;
import java.util.Arrays;
public class Example{
public static void main(String[] args) {
//创建File对象,并指定文件路径
File file = new File("D:\\FFOutput");
//判断是否是目录
if(file.isDirectory()){
String[] list = file.list();
Arrays.stream(list).forEach(System.out::println);
}
}
}
需求:如果只获取特定类型的文件,使用list(FilenameFilter filter)方法过滤文件。
FilenameFilter:函数式接口,即文件过滤器
内部有抽象方法accept(File dir,String name)对文件筛选。
实例代码2
import java.io.File;
public class Example{
public static void main(String[] args) {
File file = new File("D:\\FFOutput");
//判断是否是目录
if(file.isDirectory()){
//过滤出以flv结尾的文件
String[] lists = file.list(((dir, name) -> name.endsWith(".flv")));
for (String list : lists) {
System.out.println(list);
}
}
}
}
需求:如果目录下还有子目录,如果想得到所有子目录下的File类型对象,则使用listFiles()方法
实例代码3
import java.io.File;
public class Example{
public static void main(String[] args) {
File files = new File("D:\\FFOutput");
fileDir(files);
}
//迭代目录或文件
public static void fileDir(File files){
if(files.isDirectory()){
File[] files1 = files.listFiles();
for (File file : files1) {
if(file.isDirectory()){
fileDir(file);
}
else{
System.out.println(file.getName());
}
}
}else{
System.out.println(files.getName());
}
}
}
需求:用delete()方法删除某一目录下的文件或文件夹
用法:先判断目录下是否有文件,如果存在则需要先删除内部文件,然后再删除空的文件夹
实例代码
import java.io.File;
public class Example{
public static void main(String[] args) {
File files = new File("D:\\java实验");
deleteDir(files);
}
public static void deleteDir(File files){
if(files.isDirectory()){
File[] files1 = files.listFiles();
for (File file : files1) {
if(files.isDirectory()){
deleteDir(file);
}
file.delete();
}
}
files.delete();
}
}
注意:delete()方法删除的文件不经过回收站,永久性删除!!!谨慎使用!!!
作用:可以随机的从文件的任意位置开始执行读写操作
RandomAccessFile类的构造方法
方法声明 | 功能描述 |
---|---|
RandomAccessFile(File file,String mode) | 使用参数file指定被访问的文件,并使用mode来指定访问模式 |
RandomAccessFile(String name,String mode) | 使用参数name指定被访问文件的路径,并使用mode来指定访问模式 |
参数mode指定访问文件的模式,即文件的操作权限
参数mode的4个值:
RandomAccessFile类对象中包含一个记录指针来标识当前读写处的位置。
RandomAccessFile类中的常用方法
方法声明 | 功能描述 |
---|---|
long getFilePointer() | 获取当前记录指针所在的位置 |
void seek(long pos) | 设定读写指针的位置,与文件开头相隔pos个字节数 |
int skipBytes(int n) | 使读写指针从当前位置开始,跳过n个字节 |
void write(byte[] b) | 将指定的字节数组写入到这个文件,并将指针移到其后面 |
void setLength(long newLength) | 设置此文件的长度 |
final String readLine() | 从指定文件当前指针读取下一行内容 |
实例代码
import java.io.RandomAccessFile;
public class Example{
public static void main(String[] args) throws Exception {
//创建RandomAccessFile对象,并以读写模式打开time.txt文件
RandomAccessFile raf = new RandomAccessFile("time.txt", "rw");
int times = Integer.parseInt(raf.readLine()) - 1;
if(times > 0){
System.out.println("您还可以使用"+times+"次!");
raf.seek(0);
raf.write((times+"").getBytes());
}else{
System.out.println("试用次数已经用完");
}
//关闭随机存取文件流并释放任何系统
raf.close();
}
}
java的对象序列化作用:将对象永久性地保存到磁盘上
对象序列化:将一个java对象转换为一个I/O流中字节序列的过程。
对象的反序列化:将I/O流中的字节序列恢复成java对象的过程。
在Java中,实现可序列化必须实现Serializable或Externalizable这两个接口之一
Serializable或Externalizable区别
实现Serializable接口(常用) | 实现Externalizable接口 |
---|---|
系统自动存储必要的信息 | 由程序员决定所存储的信息 |
java内部支持,易于实现,实现该接口即可 | 接口中提供了两个空方法,实现复杂 |
性能差 | 性能较好 |
NIO采用内存映射文件的方式处理输入输出
NIO与传统I/O流的区别
NIO的三大核心部分:Buffer、channel、Selector
本节用到的架构:
要想创建Buffer对象,通过子类的static XxxBuffer allocate(int capacity)方法来实现
CharBuffer buffer = CharBuffer.allocate(6);
Buffer的3个重要概念
Buffer抽象类的常用方法
方法声明 | 功能描述 |
---|---|
int capacity() | 获取缓冲区的大小 |
Buffer clear() | 清空缓冲区,即position为0,limit为capacity |
Buffer flip() | 反转缓冲区,即将limit设置为当前position位置,再将position设置为0 |
boolean hasRemaining() | 判断position和limit之间是否还有元素 |
int limit | 获取Buffer的limit位置 |
Buffer limit(int newLimit) | 获取limit的值,并返回一个新的limit缓冲区对象 |
Buffer mark() | 获取Buffer的标记,只能在0与position之间做标记 |
int position() | 获取Buffer中position值 |
Buffer position(int newPosition) | 设置Buffer的position值 |
int remaining() | 获取当前位置和界限之间的元素个数 |
Buffer reset() | 将此缓冲区的位置重置为先前标记的位置 |
Buffer rewind() | 倒带缓冲区,将position为0,取消设置的标记 |
Buffer的所有子类中都额外提供了**put()和get()**方法用于向Buffer中放入数据和取出数据
实例代码
import java.nio.CharBuffer;
public class Example {
public static void main(String[] args) {
//创建CharBuffer对象
CharBuffer buffer = CharBuffer.allocate(6);
System.out.println("容量:"+buffer.capacity()); //6
System.out.println("界限值:"+buffer.limit()); //6
System.out.println("初始位置:"+buffer.position()); //0
//向CharBuffer对象中放入3个元素
buffer.put('a');
buffer.put('b');
buffer.put('c');
buffer.put('d');
System.out.println("加入元素后的界限值:"+buffer.limit()); //6
System.out.println("加入元素后的位置:"+buffer.position()); //4
//执行flip()方法
buffer.flip();
System.out.println("执行flip()后的界限值:"+buffer.limit()); //4
System.out.println("执行flip()后的位置::"+buffer.position()); //0
//取出第1个元素
System.out.println("取出第一个元素为:"+buffer.get()); //a
System.out.println("取出元素后的界限值:"+buffer.limit()); //4
System.out.println("取出元素后的位置:"+buffer.position()); //1
//执行clear()方法
buffer.clear();
System.out.println("执行clear()后的界限值:"+buffer.limit()); //6
System.out.println("执行clear()后的位置:"+buffer.position()); //0
//取出第1个元素
System.out.println("取出第一个元素为:"+buffer.get(0)); //a
System.out.println("取出元素后的界限值:"+buffer.limit()); //6
System.out.println("取出元素后的位置:"+buffer.position()); //0
}
}
注意:执行完clear()方法后,Buffer对象中的数据依然存在,并且通过索引取出元素值后,position的值依然为0不变。
Channel是一个接口对象,特点:
Channel对象是通过传统I/O的getChannel()方法来获取对应的Channel。
注意:不同的实现类所获取的Channel是不同的。
详解FileChannnel类
FileChannel类的常用方法
方法声明 | 功能描述 |
---|---|
long position() | 返回该通道的文件位置 |
int read(ByteBuffer dst) | 从此通道读取一个字节序列给缓冲区dst |
int read(ByteBuffer dst,long position) | 从位置position开始,从此通道读取一个字节序列给缓冲区dst |
long read(ByteBuffer[] dists,int offfset,int length) | 从此通道读取一个字节序列给缓冲区dsts的子序列 |
long size() | 返回该通道文件的当前大小 |
long transferTo(long position,long count,目标通道) | 读取该通道从位置position开始,长count的字节数,并将它们写入目标通道 |
int write(ByteBuffer src) | 将缓冲区src写入这个通道的字节序列 |
long write(ByteBuffer[] srcs,int offset,int length) | 将缓冲区srcs的子序列中写入该通道的字节序列 |
int write(ByteBuffer src,long position) | 将缓冲区src从位置position开始向通道写入一个字节序列 |
实例代码
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
public class Example {
public static void main(String[] args) throws Exception {
//获取读取文件的通道
RandomAccessFile in = new RandomAccessFile("in.jpg", "rw");
FileChannel inChannel = in.getChannel();
//获取复制目标文件的通道
RandomAccessFile out = new RandomAccessFile("dest_01.jpg", "rw");
FileChannel outChannel = out.getChannel();
//使用transferTo()方法整体复制
long to = inChannel.transferTo(0, inChannel.size(), outChannel);
if(to>0){
System.out.println("复制成功");
}
//关闭资源
in.close();
out.close();
inChannel.close();
outChannel.close();
}
}
NIO.2中提供了两个工具类paths类和Files类
Paths类提供了两个静态方法来创建Path对象
方法声明 | 功能描述 |
---|---|
Path Paths.get(URL url) | 通过文件路径创建Path对象 |
(另一个极少用)
Path接口的常用方法
方法声明 | 功能描述 |
---|---|
boolean endsWith(String other) | 判断当前路径是否以字符串other结尾 |
Path getName(int index) | 获取此路径的名称元素作为路径对象 |
int getNameCount() | 返回路径中名称元素的数量 |
Path getParent() | 返回父路径,没有返回null |
Path getRoot() | 返回根路径没有则返回null |
Path toAbsolutePath() | 返回此路径的绝对路径的路径对象 |
URI toUri() | 返回此路径的URL地址 |
实例代码
import java.nio.file.Path;
import java.nio.file.Paths;
public class Example {
public static void main(String[] args) throws Exception {
Path path = Paths.get("C:\\Users\\lenovo\\Desktop\\MarkDown");
System.out.println("path的父路径:"+path.getParent());
System.out.println("path的根路径:"+path.getRoot());
System.out.println("path的路径名称数"+path.getNameCount());
//循环输出路径名称
for (int i = 0; i < path.getNameCount(); i++) {
Path name = path.getName(i);
System.out.println("索引为"+i+"的路径的名称:"+name);
}
System.out.println("path的URL路径为"+path.toUri());
System.out.println("path的绝对路径为"+path.toAbsolutePath());
}
}
Files工具类的常用方法
方法声明 | 功能描述 |
---|---|
static Path createDirectories(Path dir,FileAttribute>…attrs) | 创建多级文件目录 |
static Path createFile(Path path,FileAttribute>…attrs) | 创建一个空文件,如果文件存在,则创建失败 |
static Path copy(Path source,Path target,参数) | 将一个文件复制到目标文件,参数:指定如何复制 |
static ListreadAllLines(Path path) | 从文件中读取所有行 |
static long size(Path path) | 返回文件的大小 |
static Stream list(Path dir) | 将指定路径dir转化为Stream流对象 |
static Path write(Path path,集合,写入模式) | 将文本行写入文件,并传入指定的写入模式 |
实例代码
public class Example {
public static void main(String[] args) throws Exception {
//文件目录不存在,否则异常
Path directortypath = Paths.get("D:\\java的Files工具类\\实验");
Files.createDirectories(directortypath);
System.out.println("创建目录成功!");
//定义一个文件路径的Path对象
//文件名称不存在,否则异常
Path file = Paths.get("D:\\java的Files工具类\\实验\\world.txt");
Files.createFile(file);
//根据Path对象创建一个文件
ArrayList<String> list = new ArrayList<>();
list.add("这是一个测试文件");
Files.write(file,list, StandardOpenOption.APPEND);
List<String> lines = Files.readAllLines(file);
System.out.println("文件大小:"+Files.size(file));
System.out.println("文件中的内容:"+lines);
}
}