Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。
一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。
NO. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public File(String pathname) | 构造 | 传递完整文件操作路径 |
2 | public File(File parent, String child) | 构造 | 设置父路径与子文件名称 |
3 | public boolean createNewFile() throws IOException | 普通 | 创建新文件 |
4 | public boolean exists() | 普通 | 判断给定路径是否存在 |
5 | public boolean delete() | 普通 | 删除指定路径的文件(路径不删除,保留住) |
6 | public File getParentFile() | 普通 | 取得当前路径的父路径 |
7 | public boolean mkdirs() | 普通 | 创建多级目录 |
8 | public long length() | 普通 | 取得文件大小,以字节为单位返回 |
9 | public boolean isFile() | 普通 | 判断给定路径是否是文件 |
10 | public boolean isDirectory() | 普通 | 判断给定路径是否是目录 |
11 | public long lastModified() | 普通 | 取得文件的最后一次修改日期(以毫秒为单位) |
12 | public String[] list() | 普通 | 列出指定目录中的全部内容 |
13 | public File[] listFiles() | 普通 | 列出所有的路径以File类对象包装 |
文件基本操作
// An highlighted block
public class Main {
//File.separator路径分隔符 类似\
public static void main(String args[]) throws Exception{
File file = new File("E:" + File.separator + "test.txt");//设置一个文件的路径
if(file.exists()){
//判读文件是否存在
file.delete();//存在,则删除文件
}else {
file.createNewFile();//不存在,则创建文件
}
}
}
创建带路径的文件
public class Main {
public static void main(String args[]) throws Exception{
File file = new File("E:" + File.separator+"hello"+File.separator+ "test.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdir();//创建父路径
}
file.createNewFile();//创建新文件
}
}
注意:在创建文件前,需要先判断父路径是否存在,如果不存在则一定要先创建父目录(否则会出现“java.io.IOException:系统找不到指定路径”),由于目录会存在多级目录的情况,所以需要使用mkdirs()方法进行创建。
取得文件或者目录的信息
public class Main {
public static void main(String args[]) throws Exception{
File file = new File("E:" +File.separator+ "my.jpg");
if(file.exists()){
System.out.println("是否是文件:"+file.isFile());
System.out.println("是否是目录:"+file.isDirectory());
System.out.println("文件大小:"+String.format("%.2f",(double)file.length()/1024)+"KB");
System.out.println("上次修改文件时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(file.lastModified())));
}
}
}
列出目录信息
public class Main {
public static void main(String args[]) throws Exception{
File file = new File("E:" +File.separator);
if(file.isDirectory()){
File[] files = file.listFiles();
for(int i = 0; i < files.length; i++){
System.out.println(files[i]);
}
}
}
}
结果:E:\$RECYCLE.BIN
E:\my.jpg
E:\origin
E:\reactproject
E:\System Volume Information
列出指定目录下的所有文件及子目录信息
在每一个目录中有可能还会存在其他子目录,并且还可能有更深层次的子目录,所以为了可以列出所有的内容,应该判断每一个给定的路径是否是目录。如果是目录应该继续列出,这样的操作最好使用递归的方式完成。
public class Main {
public static void main(String args[]) throws Exception{
File file = new File("E:" +File.separator);
list(file);
}
public static void list(File file){
if(file.isDirectory()){
File[] files = file.listFiles();
if(files != null){
for(int i = 0; i < files.length; i++){
list(files[i]);
}
}
}
System.out.println(file);
}
}
在java中针对数据流的操作也分为输入与输出两种方式,而且针对此操作提供了以下两类支持。
字节流(JDK1.0开始提供):InputStream(输入字节流)、OutputStream(输出字节流);
字符流(JDK1.1开始提供):Reader(输入字符流)、Writer(输出字符流)
在java.io包中,四个操作流的类全部都属于抽象类,所以在使用这些类时,一定要通过子类对象的向上转型来进行抽象类对象的实例化操作。
NO. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public void close() throws IOException | 普通 | 关闭字节输出流 |
2 | pubilc void flush() throws IOException | 普通 | 强制刷新 |
3 | public abstract void write(int b) throws IOException | 普通 | 输出单个字节 |
4 | public void write(byte[] b) throws IOException | 普通 | 输出全部字节数组 |
5 | public void write(byte[] b, int off,int len) throws IOException | 普通 | 输出部分字节数组 |
FileOutputStream类的常用方法
NO. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public FileOutputStream (File file) throws FileNotFoundException | 构造 | 将内容输出到指定路径,如果文件已存在,则使用新的内容覆盖旧的内容 |
2 | pubilc FileOutputStream (File file, boolean append) throws FileNotFoundException | 构造 | 如果将布尔参数设置为true,表示追加新的内容到文件中 |
//文件内容的输出
public class Main {
public static void main(String args[]) throws Exception{
//1.定义要输出的文件路径
File file = new File("E:" +File.separator+"hello"+File.separator+"test.txt");
//2.判断文件父路径是否存在
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//3.文件不存在,不需要手工调用createNewFile(),构造方法会自动创建一个空文件
OutputStream output = new FileOutputStream(file);
String str = "aaa";
byte[] bytes = str.getBytes();
output.write(bytes);
output.close();
}
输出单个字节
for(int x=0; x < data.length; x++){
output.write(data[x]);
}
输出部分字节数组
//设置了数组的开始索引和长度
output.write(data,6,6)
NO. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public void close() throws IOException | 普通 | 关闭字节输入流 |
2 | public abstract int read(int b) throws IOException | 普通 | 读取单个字节 |
3 | public int read(byte[] b) throws IOException | 普通 | 将数据读取到字节数组中,同时返回读取长度 |
4 | public int read(byte[] b, int off,int len) throws IOException | 普通 | 将数据读取到部分字节数组中,同时返回长度 |
NO. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public FileInputStream (File file) throws FileNotFoundException | 构造 | 设置要读取文件数据的路径 |
数据读取操作
public class Main {
public static void main(String args[]) throws Exception{
//1.定义要输出的文件路径
File file = new File("E:" +File.separator+"hello"+File.separator+"test.txt");
//2.判断文件是否存在
if(file.exists()){
InputStream inputStream = new FileInputStream(file);
//3.设置一个长度为1024的byte数组接收数据
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
inputStream.close();
//4.讲读取的字节数组变成字符串进行输出
System.out.println(new String(bytes,0,len));
}
}
}
采用while循环实现输入流操作
public class Main {
public static void main(String args[]) throws Exception{
//1.定义要输出的文件路径
File file = new File("E:" +File.separator+"hello"+File.separator+"test.txt");
//2.判断文件是否存在
if(file.exists()){
InputStream inputStream = new FileInputStream(file);
byte[] bytes = new byte[1024];
int foot = 0; //设置字节数组脚标
int temp = 0; //获取读取的字节数据
// temp = inputStream.read() 表示将读取到个单个字节数据给temp变量
while ((temp = inputStream.read()) != -1){
// foot++ 可以看成 i = foot++ i先等于0 ,然后foot自增1
bytes[foot++] = (byte) temp;
}
inputStream.close();
//3.讲读取的字节数组变成字符串进行输出
System.out.println(new String(bytes,0,foot));
}
}
}
NO. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public void close() throws IOException | 普通 | 关闭字符输出流 |
2 | pubilc void flush() throws IOException | 普通 | 强制刷新 |
3 | public Write append(CharSequence csq) throws IOException | 普通 | 追加数据 |
4 | public void write(String str) throws IOException | 普通 | 输出字符串数据 |
5 | public void write(char[] b) throws IOException | 普通 | 输出字符数组数据 |
FileWriter类常用方法
NO. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public FileWriter (File file) throws IOException | 构造 | 将内容输出到指定路径,如果文件已存在,则使用新的内容覆盖旧的内容 |
2 | pubilc FileWriter (File file, boolean append) throws FileNotFoundException | 构造 | 如果将布尔参数设置为true,表示追加新的内容到文件中 |
使用Writer类实现内容输出
public class Main {
public static void main(String args[]) throws Exception{
//1.定义要输出的文件路径
File file = new File("E:" +File.separator+"hello"+File.separator+"test.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
Writer fileWriter = new FileWriter(file);
fileWriter.write("hello");
fileWriter.close();
}
}
NO. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public void close() throws IOException | 普通 | 关闭字符输入流 |
2 | public int read() throws IOException | 普通 | 读取单个字符 |
3 | public int read(char[] b) throws IOException | 普通 | 将数据读取到字数符组中,同时返回读取长度 |
4 | public long skip(long b) throws IOException | 普通 | 跳过字节长度 |
使用Reader读取数据
public class Main {
public static void main(String args[]) throws Exception{
//1.定义要输出的文件路径
File file = new File("E:" +File.separator+"hello"+File.separator+"test.txt");
if(file.exists()){
Reader fileReader = new FileReader(file);
char[] chars = new char[1024];
int len = fileReader.read(chars);
fileReader.close();
System.out.println(new String(chars,0,len));
}
}
}
➢在使用OutputStream输出数据的时候即使最后没有关闭输出流,那么内容也可以正常输出,但是反过来如果使用的是字符输出流Writer,在执行到最后如果不关闭输出流,那么就表示在缓冲区之中处理的内容不会被强制性的清空,所以就不会输出数据。如果现在有特殊情况不能够关闭字符输出流,可以使用flush()方法强制清空缓冲区。
强制清空缓冲区
public class Main {
public static void main(String args[]) throws Exception{
//1.定义要输出的文件路径
File file = new File("E:" +File.separator+"hello"+File.separator+"test.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
Writer fileWriter = new FileWriter(file);
fileWriter.write("hahaha");
fileWriter.flush(); //强制清空缓冲区,不然文件中没数据
}
}
➢虽然字节流与字符流表示两种不同的数据流操作,但是这两种流彼此间是可以实现互相转换的,而要想实现这样的转换就可以通过InputStreamReader、 OutputStreamWriter两个类实现。 首先来观察一下这两个类的继承结构以及构造方法:
名称 | InputStreamReader | OutputStreamWriter |
---|---|---|
定义结构 | public class InputStreamReader extends Reader | public class OutputStreamWriter extends Writer |
构造方法 | public InputStreamReader(InputStream in) | public OutputStreamWriter(OutputStream out) |
实现字节输出流转换字符输出流
public class Main {
public static void main(String args[]) throws Exception{
//1.定义要输出的文件路径
File file = new File("E:" +File.separator+"hello"+File.separator+"test.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
OutputStream output = new FileOutputStream(file);
//将字节输出流转换为字符输出流
OutputStreamWriter out = new OutputStreamWriter(output);
out.write("aaa");
out.close();
}
}
➢现在要求实现一个文件的拷贝操作,在拷贝的过程中利用初始化参数设置拷贝的源路径与目标路径,同时在本程序执行时可以拷贝任何的文件,例如:图片、视频、文本等。
➢对于此时的要求首先必须确认要使用何种数据流进行操作,由于程序要求可以拷贝任意类型的文件,
所以很明显必须利用字节流(InputStream. OutputStream) 类完成,而对于具体的拷贝操作实现,就有两种做法:
➢做法二:采用边读边的操作方式,每次从源文件输入流中读取部分数据, 而后将这部分数据交给输出流输出, 这样的做法不会5用较大的内存空间,
但是会适当损耗-些时间(可以通过限制文件大小来避免此类问题)
待定
➢计算机中所有的信息组成都是二进制数据, 那么所有能够描述出的中文文字都是经过处理后的结果。在计算机的世界里,所有的语言文字都会使用编码来进行描述,例如:最常见的编码是ASC |I码。在实际的工作里面最为常见的几种编码如下:
➢UTF编码(Unicode Transformation Format) :是一-种UNICODE的可变长度编码,常见的编码为UTF -8编码;
public class Main {
public static void main(String args[]) throws Exception{
//获取系统中的环境属性中的文件编码
System.out.println(System.getProperty("file.encoding"));
}
}
结果:UTF-8
程序中出现乱码
public class Main {
public static void main(String args[]) throws Exception{
//1.定义要输出的文件路径
File file = new File("E:" +File.separator+"hello"+File.separator+"test.txt");
OutputStream out = new FileOutputStream(file);
out.write("厚度赛".getBytes("ISO8859-1"));
out.close();
}
}
//文件内容为:???
➢在流的操作中除了进行文件的输入与输出操作之外,也可以针对于内存进行同样的操作。假设说现在某一种应用, 需要进行I0操作,但是又不希望在磁盘上产生一些文件的时候, 就可以将内存当作一个临时文件进行操作。 在Java中,针对于内存操作提供有两组类:
➢字节内存流: ByteArrayInputStream (内存字节输入流)、ByteArrayOutputStream (内存字节输出流) ;
➢字符内存流: CharArrayReader (内存字符输入流)、CharArrayWriter (内存字符输出流)。
实现大小写字母转换
public class Main {
public static void main(String args[]) throws Exception{
String str = "www.baidu.com";
//将要读取的数据设置到内存输入流中
InputStream input = new ByteArrayInputStream(str.getBytes());
OutputStream output = new ByteArrayOutputStream();
int temp = 0;
while ((temp = input.read()) != -1){
//将小写字母转换为大写字母
output.write(Character.toUpperCase(temp));
}
System.out.println(output);
input.close();
output.close();
}
}
结果:WWW.BAIDU.COM
实现文件的合并
public class Main {
public static void main(String args[]) throws Exception{
File fileA = new File("E:"+File.separator+"hello"+File.separator+"a.txt");
File fileB = new File("E:"+File.separator+"hello"+File.separator+"test.txt");
InputStream inputA = new FileInputStream(fileA);
InputStream inputB = new FileInputStream(fileB);
ByteArrayOutputStream output = new ByteArrayOutputStream();
int temp = 0;
//读取文件中的字节内容
while ((temp = inputA.read()) != -1){
//将文件中的字节数据输出到内存流
output.write(temp);
}
while ((temp = inputB.read()) != -1){
output.write(temp);
}
//将内容作为字节数组取出
byte[] data = output.toByteArray();
output.close();
inputA.close();
inputB.close();
System.out.println(new String(data));
}
}
结果:����aaa //乱码是因为之前设置了文件编码
➢在java.io包中OutputStream是进行输出操作的最核心控制类,但是利用OutputStream会存在有一个问题: 所有的输出数据必须以字节类型的数据为主。也就是说如果现在要输出的数据是int (Integer) 、double (Double) 、java.util.Date等 常用类型都需要将其转换为字节后才可以输出。为了解决这样的矛盾问题,在java.io包中又专[ ]提供了一-组打印流 (字节打印流: PrintStream、 字符打印流: PrintWriter) 方便用户的输出操作
➢java.io.OutputStream类主要是进行数据输出,所以如果要设计更加合适的打印流操作类,那么就必须可以解决OutputStream输出数据类型有限(只有byte类型)的问题,这个时候可以采用一 种包装设计的模式,即:将OutputStream类利用其它类进行包装,組在这个类中提供有各种常见数据类型的输出操作,这样胪在进行输出操作时就可以回避掉字节数据的操作。
打印流
➢OutputStream提供 了核心的数据输出操作标准,但是为了更方便的实现输出操作,在java.io包中提供有两个数据打印流的操作类: PrintStream (打印字节流)、PrintWriter (打印字符流) ,以PrintStream类为例, 此类的继承结构如图所示。
PrintStream类的常用操作方法
NO. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public PrintStream (OutputStream out) | 构造 | 通过已有OutputStream确定输出目标 |
2 | pubilc void print (数据类型,参数名称) | 普通 | 输出各种常见数据类型 |
3 | pubilc void println (数据类型,参数名称) | 普通 | 输出各种常见数据类型,并追加一个换行 |
使用PrintStream类实现输出
public class Main {
public static void main(String args[]) throws Exception{
File file = new File("E:"+File.separator+"hello"+File.separator+"test.txt");
OutputStream output = new FileOutputStream(file);
PrintStream pu = new PrintStream(output);
//输出 “你好” 到文件里面
pu.print("你好");
pu.println("www");
pu.println(1.1);
pu.close();
}
}
PrintStream类的改进
➢rintStram类在最初设计时主要是为了弥补OutputStream输出类的功能不足,但是从JDK 1.5开始,为PrintStream增加 了格式化输出的支持方法: public PrintStream printf(String format, bjet… args)。利用这些方法可以使用像C语言那样的数据标记实现内容填充,常见的输出标记为:整数(%d) 、字符串(%s) 、小数(%m.nf) 、字符(%c)。
public class Main {
public static void main(String args[]) throws Exception{
String name = "小李";
int age = 19;
double score = 59.9;
File file = new File("E:"+File.separator+"hello"+File.separator+"test.txt");
OutputStream output = new FileOutputStream(file);
PrintStream pu = new PrintStream(output);
pu.printf("姓名:%s,年龄:%d,分数:%5.2f",name,age,score);
pu.close();
}
}
NO. | 常量 | 类型 | 描述 |
---|---|---|---|
1 | public static final PrintStream err | 常量 | 显示器上错误输出 |
2 | pubilc static final PrintStream out | 常量 | 显示器上信息输出 |
3 | pubilc static final PrintStream in | 常量 | 键盘数据输入 |
错误输出
public class Main {
public static void main(String args[]) throws Exception{
try {
//此处会抱一个异常
Integer.parseInt("abc");
}catch (Exception e){
System.err.println(e);
}
}
}
结果:java.lang.NumberFormatException: For input string: "abc"
屏幕信息输出
public class Main {
public static void main(String args[]) throws Exception{
System.out.println("abc");
}
}
键盘数据输入
public class Main {
public static void main(String args[]) throws Exception{
InputStream in = System.in;
StringBuffer buffer = new StringBuffer();
System.out.print("请输入数据:");
int temp = 0;
while ((temp = in.read()) != -1){
//这里这样设置字符的ASCII 可以自动转换为int
if(temp == '\n'){
break;
}
buffer.append(temp);
}
System.out.println(buffer);
}
}
结果:请输入数据:哈哈
229147136229147136
➢为了可以进行完整数据的输入操作,最好的做法是采用缓冲区的方式对输入的数据进行暂存,而后程序可以利用输入流-次性读取内容 ,如图所示,这样就可以避免输入中文时的读取错乱问题。
➢在java.i0包中如果要使用缓冲区进行数据操作, 提供有两种操作流:
➢字符缓冲区流: BufferedReader、 BufferedWriter; .
➢字节缓冲区流: BufferedInputStream、 BufferedOutputStream;
➢以上给出的四个操作类中,最为重要的就是BufferedReader类,此类是Reader的子类,属于字符缓冲输入流,而如果要处理中文数据,字符流是最方便的,
BufferedReader类的常用方法如表所示。
NO. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public BufferedReader | 构造 | 设置一个字符输入流 |
2 | pubilc String readLine() throws IOException | 普通 | 读取一行数据,默认以’\n‘ 为分隔符 |
字节输入流转字符缓冲输入流
➢如果要想使用BufferedReader类来处理System.in的操作就会出现-个问题,BufferedReader是Reader的子类, 并且构造方法中也要接收Reader类型,而System.in是InputStream类型, 所以此处就必须将InputStream类型转换为Reader类型,那么就可以利用InputStreamReader类来实现这-转换操作
键盘数据输入的标准格式
public class Main {
public static void main(String args[]) throws Exception{
// System. in是InputStream类对象,BufferedReader的构造方法 里面需要接收Reader类对象
//利用InputStreamReader将字节流对象变为字符流对象
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
System.out.print("请输入数据: ");
String str = buf.readLine();
//以回车作为换行
System.out.println("输入的内容: " + str);
}
}
结果:请输入数据: 多好多好
输入的内容: 多好多好
判断输入内容
public class Main {
public static void main(String args[]) throws Exception {
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
boolean flag = true; //编写- -个循环的逻辑
while (flag) {
//判断标志位
System.out.print("请输入年龄: ");
//提示信息
String str = buf.readLine();
//以回车作为换行
if (str.matches("\\d{1,3}")) {
//输入数据由数字组成
System.out.println("年龄是:" + Integer.parseInt(str));
flag = false;//退出循环
} else {
System.out.println("年龄输入错误,应该由数字所组成。");
}
}
}
}
结果:请输入年龄: 20
年龄是:20
读取文件
public class Main {
public static void main(String args[]) throws Exception {
File file = new File("E:"+File.separator+"hello"+File.separator+"test.txt");
BufferedReader buf = new BufferedReader(new FileReader(file));
String str = null;
while ((str = buf.readLine()) != null){
System.out.println(str);
}
buf.close();
}
}
结果:姓名:小李,年龄:19,分数:59.900
➢从JDK 1.5开始增加有一个java.util.Scanner的程序类, 利用这个类可以方便的实现数据的输入操作,但是Scanner类并没有定义在java.io包中,而是定义在了java.util包中,所以此类是一个工具类, 而此类的继承关系如图所示。
Scannner类中常用的方法
NO. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public Scanner(InputStream in) | 构造 | 接收InputStream输入流对象,此为输入源 |
2 | pubilc boolean hasNext() | 普通 | 判断是否有数据输入 |
3 | pubilc String next() | 普通 | 取出输入数据,以String形式返回 |
4 | pubilc boolean hasNextXxx() | 普通 | 判断是否有指定类型数据存在 |
5 | pubilc 数据类型 nextXxx() | 普通 | 取出指定数据类型的数据 |
6 | pubilc Scanner userDelimiter(String pattern) | 普通 | 设置读取的分隔符 |
利用Scannner实现键盘数据输入
public class Main {
public static void main(String args[]) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入内容:");
if(scanner.hasNext()){
System.out.println("输入内容:"+scanner.next());
}
scanner.close();
}
}
结果:请输入内容:哈哈
输入内容:哈哈
输入一个数字 double
public class Main {
public static void main(String args[]) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入内容:");
if(scanner.hasNextDouble()){
double aDouble = scanner.nextDouble();
System.out.println("输入内容:"+aDouble);
}else {
System.out.println("输入的不是数字");
}
scanner.close();
}
}
正则验证–出生日期
public class Main {
public static void main(String args[]) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入内容:");
if(scanner.hasNext("\\d{4}-\\d{2}-\\d{2}")){
String bir = scanner.next("\\d{4}-\\d{2}-\\d{2}");
System.out.println("输入内容:"+bir);
}else {
System.out.println("输入的不是出生日期格式");
}
scanner.close();
}
}
读取文件
public class Main {
public static void main(String args[]) throws Exception {
File file = new File("E:" + File.separator + "hello" + File.separator + "test.txt");
InputStream fileInputStream = new FileInputStream(file);
Scanner scanner = new Scanner(fileInputStream);
scanner.useDelimiter("\n");
while (scanner.hasNext()){
System.out.println(scanner.next());
}
scanner.close();
}
}
结果:姓名:小李,年龄:19,分数:59.90
666