IO流操作请多参考JDK文档https://docs.oracle.com/javase/8/docs/api/
1、IO对文件与文件夹的基本操作(增删查 )。(改文件/夹的名/内容留着后面分析)
在Java中使用File类表示文件本身,可以直接使用此类完成文件的各种操作,如创建、删除等。
File类的常用方法和常量讲解:
构造方法方法或常量 | 类型 | 描述 |
---|---|---|
public static final String pathSeparator | 常量 | 与系统相关的路径分隔符字符,为方便表示字符串 |
public static final String separator | 常量 | 与系统相关的默认名称 - 分隔符字符符串 |
public File(String pathname) | 构造方法 | 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例。 如果给定的字符串是空字符串,则结果是空的抽象路径名 |
pathSeparator 和separator作为常量未大写是因为在File类出现前Java还未对命名进行规范。这可能就叫做历史遗憾吧。
方法使用:
- File(String pathname),通过将给定的路径名字符串转换为抽象路径名,来创建新的 File实例。
- public boolean delete(),删除由此抽象路径名表示的文件或目录。 如果此路径名表示目录,则目录必须为空才能删除。
- public boolean exists(),测试此抽象路径名表示的文件或目录是否存在。
- public boolean mkdir(),创建由此抽象路径名命名的目录。
- public String[] list(),列出全部名称,返回一个字符串数组
- public File[] listFiles(),列出全部的路径,返回一个File对象数组。
- public boolean isDirectory(),测试此抽象路径名表示的文件是否为目录。
public class FileDemo01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//1、给出完整路径
//使用File.separator能表示自己系统目录分割符,如Windows中为“\”
String folderPath="F:"+File.separator+"IO";
String filePath=folderPath+File.separator+"text.txt";
//创建文件夹与文件
File folder=new File(folderPath);
createFolder(folder);
File file=new File(filePath);
createFile(file);
//列出文件与文件夹
list(file,folder);
}
//创建文件夹
static void createFolder(File folder) {
//创建文件夹
folder.mkdir();
}
//创建文件
static void createFile(File file) {
//2、判断文件是否存在
if(file.exists()) {
//如果文件存在,删除
file.delete();
}else {
try {
//如果文件不存在,根据给出的路径创建新文件
file.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//列出文件夹的内容与目录
static void list(File file,File folder) {
//判断是否是目录
if(folder.isDirectory()) {
System.out.println(folder.getPath()+"路径是目录");
System.out.println("--------------");
//如果目录不为空并且文件存在
if(folder!=null&&file.exists()) {
String list[]=folder.list();
File listFiles[]=folder.listFiles();
for (int i = 0; i < list.length; i++) {
//获取文件夹路径并列出文件名称
System.out.println(folder.getPath()+"文件夹中有:"+list[i]+"文件");
}
for (int i = 0; i < listFiles.length; i++) {
//获取文件夹路径并列出文件路径
System.out.println(folder.getPath()+"文件夹中文件路径为:"+listFiles[i]);
}
}else if((!file.exists())&&folder!=null){
System.out.println(folder.getPath()+"文件夹中没有内容!");
}
}else {
System.out.println(folder.getPath()+"文件夹不存在");
}
}
}
运行结果:
F:\IO路径是目录
--------------
F:\IO文件夹中有:text.txt文件
F:\IO文件夹中文件路径为:F:\IO\text.txt
2、RandomAccessFile
RandomAccessFile可以从指定位置开始读取信息,但是要求文件中各个数据保存长度必须固定,并且通过随机读写流实现文件内容的操作会过于复杂。一般使用字节流或字符流进行操作。知道有他就行了。
3、字节流与字符流基本操作
内存读取存储介质数据叫输入流,内存写入存储介质叫输出流。
- 1、字节流
字节流主要操作byte类型数据,以byte数据为准,主要操作类为字节输出流OutputStream类和字节输入流InputStream类。- .1.1 输出流OutputStream:
public abstract class OutputStream extends Object implements Closeable, Flushable,这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。因此我们需要OutputStream子类来实例化它。
常用子类之一
public FileOutputStream(File file) throws FileNotFoundException {}
public FileOutputStream(File file, boolean append) throws FileNotFoundException{}
- .1.1 输出流OutputStream:
public class OutputStreamDemo01 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String filePath="F:"+File.separator+"IO"+File.separator+"text.txt";
//创建文件
File file=new File(filePath);
//实例化OutputStream,并且可以在文件后面追加内容
OutputStream out=new FileOutputStream(file,true);
String str1="Hello write(byte[] b)";
//使用"\r\n"可以增加换行
String str2 = "\r\n Hello write(int t)";
//将字符串变为byte数组
byte[] b1=str1.getBytes();
byte[] b2=str2.getBytes();
//方法一、将byte数组写入数据流
out.write(b1);
//方法二、使用write(int t)将字节一个一个得输出到文件中
for (int i = 0; i < b2.length; i++) {
out.write(b2);
}
//关闭输出流
out.close();
}
}
- 1.2 输入流InputStream:
public abstract class InputStream implements Closeable
这个抽象类是表示输入字节流的所有类的超类。需要定义InputStream子类的应用InputStream必须始终提供一种返回输入的下一个字节的方法。
常用子类:FileInputStream(File file)- A当知道文件大小
a、直接从文件中读取内容
- A当知道文件大小
public class InputStreamDemo01 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String filePath="F:"+File.separator+"IO"+File.separator+"text.txt";
//创建文件
File file=new File(filePath);
//实例化InputStream
InputStream in=new FileInputStream(file);
//将所有内容读到此数组中
byte[] b=new byte[666];
//把内容取出,内容读到数组中
in.read(b);
//关闭输入流
in.close();
//将byte数组变为字符串输出
System.out.println("内容为:"+new String(b));
}
}
结果:
内容为:Hello write(byte[] b)
Hello write(int t)(很多空格......)
public int read(byte[] b) throws IOException
从该输入流读取高达byte.length字节的数据到字节数组。
直接通过read()读取文件,会将数组内容全部读出来,即使数组被内容大很多
b、将byte指定范围内容变为字符串输出
byte[] b=new byte[666];
//把内容取出,内容读到数组中
int len=in.read(b);
//关闭输入流
in.close();
//数组的长度
System.out.println("读出数据的长度:"+len);
//将byte数组变为字符串输出
System.out.println("内容为:"+new String(b,0,len));
平台上显示的内容为数组中实际的文字或数组内容,无多余空格
c、开辟指定大小的byte数组
//实例化InputStream
InputStream in=new FileInputStream(file);
//进行读操作,获取文件大小
//数组大小由文件决定
byte[] b=new byte[(int)file.length()];
//把内容取出,内容读到数组中
in.read(b);
//关闭输入流
in.close();
//将byte数组变为字符串输出
System.out.println("内容为:"+new String(b));
File类中的public long length()
返回由此抽象路径名表示的文件的长度。 如果此路径名表示目录,则返回值未指定。
通过length()方法可以获取文件的长度,能避免因不知道文件大小而造成大数组装小内容的资源浪费。
d、使用read()循环读取
能解决不知道数组大小的问题
//实例化InputStream
InputStream in=new FileInputStream(file);
//进行读操作
byte[] b=new byte[(int)file.length()];
//将文件内容依次读入数组
for (int i = 0; i < b.length; i++) {
b[i]=(byte) in.read();
}
//关闭输入流
in.close();
//将byte数组变为字符串输出
System.out.println("内容为:"+new String(b));
public int read() throws IOException
从该输入流读取下一个数据字节, 值字节作为int返回为0到255 。
- B当不知道文件大小
//实例化InputStream
InputStream in=new FileInputStream(file);
//进行读操作
byte[] b=new byte[666];
int len=0;//记录读取的数据的个数
int temp=0;//接收读取的每一个数据
//将每次读取的数据内容给temp变量,如果temp变量值不为-1,表示文件没有读完
while((temp=(in.read()))!=-1) {
b[len]=(byte)temp;
len++;
}
//关闭输入流
in.close();
//将byte数组变为字符串输出
System.out.println("内容为:"+new String(b,0,len));
文件读到末尾了,则返回的内容为-1
- 2、字符流
- 2.1字符输出流Writer
public abstract class Writer extends Object implements Appendable, Closeable, Flushable
其中的Appendable接口表示文件内容可以被追加,接收的参数事CharSequence,实际上String类也实现了此接口,所有可以直接通过此接口的方法向输出流中追加内容。
FileWriter类的构造方法:
public FileWriter(String fileName) throws IOException - a、向文件中写内容
File file=new File(path);
//通过子类实例化接口
Writer out=new FileWriter(file);
String str="Hello Writer()方法";
//字符输出
out.write(str);
out.close();
程序操作与OutputStream的操作流程相比,唯一的好好处是可以直接输出字符串不用将字符串变为byte数组后输出。
- b、向文件中追加内容
通过public FileWriter(String fileName,boolean append) throws IOException
构造一个FileWriter对象,给出一个带有布尔值的文件名,表示是否附加写入的数据。
File file=new File(path);
Writer out=new FileWriter(file,true);
String str="\r追加Hello Writer()方法";
out.write(str);
out.close();
- 2.2 字符输入流Reader
- a、从文件中读取内容
File file=new File(path);
//实例化接口
Reader input=new FileReader(file);
//读取文件内容
char[] c=new char[666];
//public int read(char[] cbuf) throws IOException
//将内容读到字符数组中,返回读入的长度。
int len=input.read(c);
input.close();
//将数组变为字符串输出
System.out.println(new String(c,0,len));
结果:
Hello Writer()方法
追加Hello Writer()方法
- b、使用循环方式读取内容
在不知道数组的大小的时候,使用循环的方式读取文件内容
File file=new File(path);
//实例化接口
Reader input=new FileReader(file);
//读取文件内容
char[] c=new char[666];
int len=0;//记录读取到的数据个数
int temp=0;//将数组读入到temp中
//使用read()读取单个字符
while((temp=input.read())!=-1) {
c[len]=(char)temp;
len++;
}
input.close();
//将数组变为字符串输出
System.out.println("数组长度为:"+len);
System.out.println(new String(c,0,len));
4、字节流与字符流区别
1、代码上的区别(见上面)
2、操作的区别
字节流在操作是本身不会使用到缓冲区(内存),是文件本身直接操作。而字符流在操作时使用了缓冲区,通过缓冲区在操作文件。
在关闭字符流时会强制将缓冲区的内容进行输出,如果程序没有关闭则缓存区内容不能输出,内容无法写进文件。
- 2.1使用字节流不关闭执行
//创建文件
File file=new File(filePath);
//实例化OutputStream,并且可以在文件后面追加内容
OutputStream out=new FileOutputStream(file);
String str="字符流与字节流的操作区别——字符流要使用缓存";
char[] c=new char[666];
byte[] b=str.getBytes();
out.write(b);
//不关闭输出流
在使用字节流直接进行输出操作时,未关闭输出流,内容仍然写入文件。
- 2.2 使用字符流不关闭操作
//创建文件
File file=new File(filePath);
//实例化OutputStream,并且可以在文件后面追加内容
Writer writer=new FileWriter(file);
String str="字符流与字节流的操作区别——字符流要使用缓存";
char[] c=new char[666];
writer.write(str);
//不关闭输出流
未关闭字符流,内容也未成功写入文件
2.3 强制性清空缓存
使用flush()可以清空缓冲区,也就能强制性将内容存到文件中。
//创建文件
File file=new File(filePath);
//实例化OutputStream,并且可以在文件后面追加内容
Writer writer=new FileWriter(file);
String str="字符流与字节流的操作区别——字符流要使用缓存";
char[] c=new char[666];
writer.write(str);
writer.flush();
//不关闭输出流
通过上面代码证明了字符流输出操作需要缓冲区,字节操作不使用缓冲区。
3、开发中,字节流使用更广泛
所有的文件在硬盘或传输时都是以字节的方式存在的,包括图片等也是以字节的方式存储的,而字符是只有在内存中才会形成。
5、字节与字符的选择与应用
需求:进行文件的复制。
分析1:复制文件必须要由源文件与目标文件两个,而且输入的源文件路径还需存在。如果不满足上面两个条件就给出错误提示。
分析2:复制的文件内容不仅仅是文字还可能需要复制图片,这时就需要使用字节流。
分析3:复制文件有两种方式:
1、将源文件内容读取到缓冲区,再一次性写入目标文件。
如果源文件内容过大可能出现缓冲区装不下,放弃。
2、不将源文件全部读取出来,而且边读边写。
public class Copy {
public static void main(String[] args) {
// TODO Auto-generated method stub
//如果文件名不足2个,给出错误提示
if(args.length!=2) {
System.out.println("输入的参数不正确");
System.out.println("如 copy 源文件路径 目标文件路径");
//退出System.exit()方法中非0就行;
System.exit(1);
}
//源文件对象
File y=new File(args[0]);
//目标文件路径
File m=new File(args[1]);
//如果源文件路径不存在,提示错误
if(!y.exists()) {
System.out.println("源文件路径不正确,请重新输入");
System.exit(1);
}
//文件输入流
InputStream input=null;
try {
input=new FileInputStream(y);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//文件输出流
OutputStream out=null;
try {
out=new FileOutputStream(m);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//确保输入流与输出流已经实例化,准备就绪
if(input!=null&&out!=null) {
//判断文件是否读取结束
int temp=0;//存每个字节
try {
//读取每一个字节
while((temp=input.read())!=-1) {
//实现边读边写操作
out.write(temp);
}
System.out.println("复制成功!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("复制失败!");
}
}
//关闭输入输出流
try {
input.close();
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
附:
在Eclipse中向main(String[] args)中的数组添加内容
进入Run——>Run Configurations找到下图所示位置填写内容。