1.File
1.File类概述和构造方法
File:它是文件和目录路径名的抽象表示
文件和目录是可以通过File封装成对象的;
对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转换为具体存在的。
方法名 | 说明 |
---|---|
File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例 |
File(String parent, String child) | 从父路径名字符串和子路径名字符串创建新的 File实例。 |
File(File parent, String child) | 从父抽象路径名和子路径名字符串创建新的 File实例。 |
import java.io.File;
public class FileDemo01 {
public static void main(String[] args) {
//File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
File f1 = new File("D:\\software\\idea\\file\\java.txt");
System.out.println(f1); //D:\software\idea\file\java.txt 重写了toString方法
//File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例。
File f2 = new File("D:\\software\\idea\\file","java.txt");
System.out.println(f2); //D:\software\idea\file\java.txt
//File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例。
File f3 = new File("D:\\software\\idea\\file");
File f4 = new File(f3,"java.txt");
System.out.println(f4); //D:\software\idea\file\java.txt
}
}
2.File类的创建功能
方法名 | 说明 |
---|---|
public boolean createNewFile() | 当具有该名称的文件尚不存在时,创建一个由该抽象路径名命名的新空文件 |
public boolean mkdir() | 创建由此抽象路径名命名的目录 |
public boolean mkdirs() | 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录 |
import java.io.File;
import java.io.IOException;
public class FileDemo02 {
public static void main(String[] args) throws IOException {
//在D:\software\idea\file目录下创建一个文件java。txt
File f1 = new File("D:\\software\\idea\\file\\java.txt"); //封装成file对象
System.out.println(f1.createNewFile()); //true 若不存在就创建并返回true;若存在就返回false
//在D:\software\idea\file目录下创建一个目录JavaSE
File f2 = new File("D:\\software\\idea\\file\\JavaSE");
System.out.println(f2.mkdir()); //true 若不存在就创建并返回true;若存在就返回false
//在D:\software\idea\file目录下创建一个多级目录JavaWEB\\HTML
File f3 = new File("D:\\software\\idea\\file\\JavaWEB\\\\HTML");
System.out.println(f3.mkdirs());
//在D:\software\idea\file目录下创建一个文件javase.txt
File f4 = new File("D:\\software\\idea\\file\\avase.txt");
}
}
3.File类删除功能
方法名 | 说明 |
---|---|
public boolean delete() | 删除由此抽象路径名表示的文件或目录 |
绝对路径和相对路径的区别:
绝对路径:完整的路径名,不需要任何其他信息就可以定位它所表示的文件。如:D:\software\idea\file\java.txt
相对路径:必须使用取自其他路径名的信息进行解释。如:myFile\java.txt
删除目录时的注意事项:
如果一个目录中有内容(目录,文件),不能直接删除。应该先删除目录中的内容,最后才能删除目录。
4.File类判断和获取功能
import java.io.File;
public class FileDemo04 {
public static void main(String[] args) {
File f = new File("myIO\\java.txt");
System.out.println(f.isDirectory());
System.out.println(f.isFile());
System.out.println(f.exists());
System.out.println("--------------");
System.out.println(f.getAbsolutePath());
System.out.println(f.getPath());
System.out.println(f.getName());
System.out.println("-------------");
File f2 = new File("D:\\software\\idea\\file");
String[] strArray = f2.list();
for (String str:strArray){
System.out.println(str);
}
System.out.println("-------------");
File[] fileArray = f2.listFiles();
for (File file:fileArray){
// System.out.println(file); //绝对路径
// System.out.println(file.getName()); //相对路径
if(file.isFile()){ //判断是否为文件
System.out.println(file.getName());
}
}
}
}
5.递归
概述:以编程的角度来看,递归指的是方法定义中调用方法本身的现象。
递归解决问题思路:
把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算。
递归解决问题要找到两个内容:
递归出口:否则会出现内存溢出;
递归规则:与原问题相似的规模较小的问题。
public class DiGuiDemo {
public static void main(String[] args) {
//回顾不死神兔问题,求第20个月兔子的对数
//每个月兔子对数:1,1,2,3,5,8,...
int[] arr = new int[20];
arr[0] = 1;
arr[1] = 1;
for (int i = 2; i < arr.length; i++) {
arr[i] = arr[i - 1] + arr[i - 2];
}
System.out.println(arr[19]);
/*
递归解决问题,首先就是要定义一个方法:
定义一个方法f(n):表示第n个月的兔子对数
那么,第n-1个月的兔子对数该为f(n-1)
StackOverflowError:当堆栈溢出发生时抛出一个应用程序递归太深
*/
System.out.println(f(20));
}
public static int f(int n) {
if (n == 1 || n == 2) {
return 1;
} else {
return f(n - 1) + f(n - 2);
}
}
}
案例:递归求阶乘
需求:用递归求5的阶乘,并把结果在控制台输出。
/*
递归求5的阶乘
*/
public class DiGuiDemo {
public static void main(String[] args) {
int result = f(5);
System.out.println("5的阶乘是:" + result);
}
//定义一个方法
public static int f(int n) {
if (n == 1) {
return 1;
} else {
return n * f(n - 1);
}
}
}
案例:遍历目录。
需求:给定一个路径,请通过递归完成遍历该目录下的所有内容,并把所有文件的绝对路径输出在控制台。
思路:
1.根据给定的路径创建一个File对象
2.定义一个方法,用于获取给定目录下的所有内容,参数为第一步创建的File对象
3.获取给定的File目录下所有的文件或者目录的File数组
4.遍历该数组,得到每一个File对象
5.判断该File对象是否是目录
是:递归调用;
不是,获取绝对路径输出在控制台
6.调用方法。
import java.io.File;
public class DiGuiDemo02 {
public static void main(String[] args) {
//1.根据给定的路径创建一个File对象
File f = new File("D:\\software\\idea\\file");
//6.调用方法。
getPath(f);
}
//2.定义一个方法,用于获取给定目录下的所有内容,参数为第一步创建的File对象
public static void getPath(File f){
//3.获取给定的File目录下所有的文件或者目录的File数组
File[] fileArray = f.listFiles();
//4.遍历该数组,得到每一个File对象
if(fileArray!=null){ //为了程序的健壮性,先判断
for (File file:fileArray){
//5.判断该File对象是否是目录
if(file.isDirectory()){ //是:递归调用;
getPath(file);
}else { //不是,获取绝对路径输出在控制台
System.out.println(file.getAbsolutePath());
}
}
}
}
}
2.字节流
1.IO流概述:
IO:输入/输出
流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输
IO流就是用来处理设备间数据传输问题的
常见的应用:文件复制;文件上传;文件下载
一般来说,IO流的分类就是按照数据类型来分的
如果我们通过记事本打开,还可以读懂里面的内容,就使用字符流,否则使用字节流。若不知道该使用哪种就用字节流。
2.字节流写数据
字节流抽象基类:
InputStream:这个抽象类是表示输入字节流的所有类的超类。
OutputStream:这个抽象类是表示字节输出流的所有类的超类。
子类名特点:子类名称都是以其父类名作为子类名的后缀
FileOutputStream:文件输出流是用于将数据写入File
FileOutputStream(String name):创建文件输出流以指定的名称写入文件。
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo01 {
public static void main(String[] args) throws IOException {
//创建字节输出流对象
FileOutputStream fos = new FileOutputStream("myIO\\fos.txt");
/*
做了三件事:
1.调用系统功能创建了文件
2.创建了字节输出流对象
3.让字节输出流对象指向创建好的文件
*/
//写数据
fos.write(97);
//最后要释放资源 void close() 关闭此文件输出流并释放与此流相关联的任何系统资源。
fos.close();
}
}
3.字节流写数据的方法
方法名 | 说明 |
---|---|
void write(int b) | 将指定的字节写入此文件输出流。一次写一个字节数据 |
void write(byte[] b) | 将 b.length字节从指定的字节数组写入此文件输出流。一次写一个字节数组数据 |
void write(byte[] b, int off, int len) | 将 len字节从指定的字节数组开始,从偏移量 off开始写入此文件输出流。一次写一个字节数组的部分数据 |
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo02 {
public static void main(String[] args) throws IOException {
//FileOutputStream(String name) 创建文件输出流以指定的名称写入文件。
FileOutputStream fos = new FileOutputStream("myIO\\fos.txt");
//FileOutputStream(File file) 创建文件输出流以写入由指定的 File对象表示的文件。
// File file = new File("myIO\\fos.txt");
// FileOutputStream fos2 = new FileOutputStream(file);
// FileOutputStream fos2 = new FileOutputStream(new File("myIO\\fos.txt"));
//void write(int b) 将指定的字节写入此文件输出流。
// fos.write(97);
// fos.write(98);
//void write(byte[] b) 将 b.length字节从指定的字节数组写入此文件输出流。
// byte[] bys = {97,98,99,100};
byte[] bys = "abc".getBytes();
fos.write(bys);
//void write(byte[] b, int off, int len) 将 len字节从指定的字节数组开始,从偏移量 off开始写入此文件输出流。
fos.write(bys,0, bys.length);
//释放资源
fos.close();
}
}
4.字节流写数据的两个小问题
字节流写数据如何实现换行?
写完数据加换行符:\r\n; \n ; \r
字节流写数据如何实现追加写入?
public FileOutputStream(String name,boolean append)
创建文件输出流以指定的名称写入文件。 如果第二个参数为true ,则字节将写入文件的末尾而不是开头。
5.字节流写数据加异常处理
finally:在异常处理时提供finally块来执行所有清除操作。比如IO流中的释放资源
特点:被finally控制的语句一定会执行,除非JVM退出。
try{
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}finally{
执行所有清除操作;
}
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo04 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("myIO\\fos.txt");
fos.write("hello".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) { //保证健壮性
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
6.字节流读数据(一次读一个字节数据)
需求:把文件fos.txt中的内容读取出来在控制台输出;
FileInputStream:从文件系统中的文件获取输入字节:
FileInputStream(String name) :通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
使用字节输入流读数据的步骤:
创建字节输入流对象;
调用字节输入流对象的读数据方法;
释放资源。
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamDemo01 {
public static void main(String[] args) throws IOException {
//创建字节输入流对象;
FileInputStream fis = new FileInputStream("myIO\\fos.txt");
//调用字节输入流对象的读数据方法;
int by ;
while ((by = fis.read()) != -1) {
System.out.print((char) by);
}
//释放资源。
fis.close();
}
}
案例:复制文本文件。
需求:把“D:\software\idea\workspace\JavaSE_Code\复制.txt”复制到模块目录下的“复制.txt”
分析:
1.复制文本文件,其实就把文本文件的内容从一个文件中读取出来(数据源),然后写入到另一个文件中(目的地)
2.数据源:D:\software\idea\workspace\JavaSE_Code\复制.txt —读数据—InputStream—FileInputStream
3.目的地:myIO\复制.txt—写数据—OutputStream—FileOutputStream
思路:
1.根据数据源创建字节输入流对象
2.根据目的地创建字节输出流对象
3.读写数据,复制文本文件(一次读取一个字节,一次写入一个字节)
4.释放资源
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyTxtDemo {
public static void main(String[] args) throws IOException {
//1.根据数据源创建字节输入流对象
FileInputStream fis = new FileInputStream("D:\\software\\idea\\workspace\\JavaSE_Code\\复制.txt");
//2.根据目的地创建字节输出流对象
FileOutputStream fos = new FileOutputStream("myIO\\复制.txt");
//3.读写数据,复制文本文件(一次读取一个字节,一次写入一个字节)
int by;
while ((by=fis.read())!=-1){
fos.write(by);
}
//4.释放资源
fos.close();
fis.close();
}
}
7.字节流读数据(一次读一个字节数组数据)
需求:把文件fos.txt中的内容读取出来在控制台输出;
使用字节输入流读数据的步骤:
创建字节输入流对象;
调用字节输入流对象的读数据方法;
释放资源。
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamDemo02 {
public static void main(String[] args) throws IOException {
//创建字节输入流对象;
FileInputStream fis = new FileInputStream("myIO\\fos.txt");
//调用字节输入流对象的读数据方法;
byte[] bys = new byte[1024]; //1024及其整数倍
int len ;
while ((len=fis.read(bys))!=-1){
System.out.println(new String(bys,0,len));
}
//释放资源。
fis.close();
}
}
案例:复制图片。
需求:把“D:\software\idea\file.png”复制到模块目录下的“file.png”;
思路:
1.根据数据源创建字节输入流对象
2.根据目的地创建字节输出流对象
3.读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
4.释放资源
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyPicture {
public static void main(String[] args) throws IOException {
//1.根据数据源创建字节输入流对象
FileInputStream fis = new FileInputStream("D:\\software\\idea\\file.png");
//2.根据目的地创建字节输出流对象
FileOutputStream fos = new FileOutputStream("myIO\\file.png");
//3.读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
byte[] bys = new byte[1024];
int len;
while ((len=fis.read(bys))!=-1){
fos.write(bys,0,len);
}
//释放资源
fis.close();
fos.close();
}
}
7.字节缓冲流
字节缓冲流:
BufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节。
BufferedOutputStream:该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用。
构造方法:
字节缓冲输入流:BufferedInputStream(InputStream in)
字节缓冲输出流:BufferedOutputStream(OutputStream out)
为什么构造方法需要的是字节流,而不是具体的文件或者路径呢?
字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作。
import java.io.*;
public class BufferStreamDemo {
public static void main(String[] args) throws IOException {
//字节缓冲输出流:BufferedOutputStream(OutputStream out)
/* FileOutputStream fos = new FileOutputStream("myIO\\fos.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);*/
/*BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myIO\\fos.txt"));
//写数据
bos.write("hello\n".getBytes());
bos.write("world\n".getBytes());*/
//字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("myIO\\fos.txt"));
//一次读一个字节数据
int by;
while ((by = bis.read()) != -1) {
System.out.print((char) by);
}
//一次读取一个字节数组数据
byte[] bys = new byte[1024];
int len;
while ((len = bis.read(bys) )!= -1) {
System.out.print(new String(bys,0,len));
}
// bos.close();
bis.close();
}
}
案例:复制视频。
需求:把“D:\software\idea\字节流复制图片.avi”复制到模块目录下的“字节流复制图片.avi”
思路:
1.根据数据源创建字节输入流对象
2.根据目的地创建字节输出流对象
3.读写数据,复制视频
4.释放资源
import java.io.*;
public class CopyAviDemo {
public static void main(String[] args) throws IOException {
//记录开始时间
long startTime = System.currentTimeMillis();
method1();
method2();
method3();
method4();
//记录结束时间
long endTime = System.currentTimeMillis();
System.out.println("共耗时:" + (endTime - startTime) + "毫秒");
}
//字节缓冲流一次读写一个字节数组
public static void method4() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\software\\idea\\字节流复制图片.avi"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myIO\\字节流复制图片.avi"));
byte[] bys = new byte[1024];
int len;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
bis.close();
bos.close();
}
//字节缓冲流一次读写一个字节
public static void method3() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\software\\idea\\字节流复制图片.avi"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myIO\\字节流复制图片.avi"));
int by;
while ((by = bis.read()) != -1) {
bos.write(by);
}
bis.close();
bos.close();
}
//基本字节流一次读写一个字节数组
public static void method2() throws IOException {
//1.根据数据源创建字节输入流对象
FileInputStream fis = new FileInputStream("D:\\software\\idea\\字节流复制图片.avi");
//2.根据目的地创建字节输出流对象
FileOutputStream fos = new FileOutputStream("myIO\\字节流复制图片.avi");
//3.读写数据,复制视频
byte[] bys = new byte[1024];
int len;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
//4.释放资源
fis.close();
fos.close();
}
//基本字节流一次读写一个字节
public static void method1() throws IOException {
//1.根据数据源创建字节输入流对象
FileInputStream fis = new FileInputStream("D:\\software\\idea\\字节流复制图片.avi");
//2.根据目的地创建字节输出流对象
FileOutputStream fos = new FileOutputStream("myIO\\字节流复制图片.avi");
//3.读写数据,复制视频
int by;
while ((by = fis.read()) != -1) {
fos.write(by);
}
//4.释放资源
fis.close();
fos.close();
}
}
3.字符流
1.为什么会出现字符流
由于字节流操作中文不是特别的方便,所以Java就提供字符流。
字符流 = 字节流 + 编码表
用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文。识别中文方式:汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数。
2.编码表
计算机中存储的信息都是二进制数表示的;我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果
按照某种规则,将字符存储到计算机中,称为编码。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码。注:按照A编码存储,必须按照A编码解析,这样才能显示正确的文本符号。否则就会导致乱码现象。
字符编码:就是一套自然语言的字符与二进制数之间的对应规则(A,65)
字符集:
是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集等
ASCII字符集:
ASCII ((American Standard Code for Information Interchange): 美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)
基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
GBXXX字符集:
GB2312:简体中文码表。一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数字符号、罗马希腊的字母、日文的假名等都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的“全角”字符,而原来在127号以下的那些就叫“半角”字符了
GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等
GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字都可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等
Unicode字符集
为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。它最多使用4个字节的数字来表达每个字母、符号、或者文字。有三种编码方案,UTF-8、UTF-16和UTF32。最为常用的UTF-8编码。
UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码
编码规则:
128个US-ASCII字符,只需一个字节编码
拉丁文等字符,需要二个字节编码
大部分常用字(含中文),使用三个字节编码
其他极少使用的Unicode辅助字符,使用四字节编码
小结:采用何种规则编码,就要采用对应规则解码,否则就会出现乱码。
3.字符串中的编码解码问题
编码:
byte[] getBytes() : 使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
byte[] getBytes(String charsetName) : 使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中
解码:
String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的String
String(byte[] bytes,String charsetName) :通过指定的字符集解码指定的字节数组来构造新的String
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class StringDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
//定义一个字符串
String s = "中国";
/*byte[] bys = s.getBytes();
System.out.println(Arrays.toString(bys)); //[-28, -72, -83, -27, -101, -67]
String ss = new String(bys);
System.out.println(ss); //中国*/
byte[] bys = s.getBytes("GBK");
System.out.println(Arrays.toString(bys)); //[-42, -48, -71, -6]
String ss = new String(bys,"GBK");
System.out.println(ss); //中国
}
}
4.字符流中的编码解码问题
字符流抽象基类
Reader:字符输入流的抽象类
Writer:字符输出流的抽象类
字符流中和编码解码问题相关的两个类:
InputStreamReader
OutputStreamWriter
import java.io.*;
public class ConversionStreamDemo {
public static void main(String[] args) throws IOException {
//OutputStreamWriter(OutputStream out) 创建一个使用默认字符编码的OutputStreamWriter。
FileOutputStream fos = new FileOutputStream("myIO\\osw.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos);
osw.write("中国");
osw.close();
//OutputStreamWriter(OutputStream out, String charsetName) 创建一个使用命名字符集的OutputStreamWriter。
// OutputStreamWriter osw1 = new OutputStreamWriter(new FileOutputStream("myIO\\osw.txt"),"UTF-8");
//InputStreamReader(InputStream in) 创建一个使用默认字符集的InputStreamReader。
//InputStreamReader(InputStream in, String charsetName) 创建一个使用命名字符集的InputStreamReader。
InputStreamReader isr = new InputStreamReader(new FileInputStream("myIO\\osw.txt"));
//一次读取一个字符数据
int ch;
while ((ch= isr.read())!=-1){
System.out.print((char)ch);
}
isr.close();
}
}
5.字符流写数据的5种方式
方法名 | 说明 |
---|---|
void write(int c) | 写一个字符 |
void write(char[] cbuf) | 写入一个字符数组 |
void write(char[] cbuf, int off, int len) | 写入字符数组的一部分 |
void write(String str) | 写一个字符串 |
void write(String str, int off, int len) | 写一个字符串的一部分 |
方法名 | 说明 |
---|---|
flush() | 刷新流,还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myIO\\osw.txt"));
osw.write(98);
// osw.flush(); //刷新流
char[] chs = {'s','d','f','z'};
osw.write(chs);
osw.write(chs,0, chs.length);
osw.close();
}
}
6.字符流读数据的2种方式
方法名 | 说明 |
---|---|
int read() | 一次读一个字符数据 |
int read(char[] cbuf) | 一次读一个字符数组数据 |
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("myIO\\osw.txt"));
/* //int read() 一次读一个字符数据
int ch;
while ((ch=isr.read())!=-1){
System.out.print((char)ch);
}*/
//int read(char[] cbuf) 一次读一个字符数组数据
char[] chs = new char[1024];
int len;
while ((len=isr.read(chs))!=-1){
System.out.print(new String(chs,0,len));
}
isr.close();
}
}
案例:复制Java文件
需求:把模块目录下的“ConversionStreamDemo.java” 复制到模块目录下的“Copy.java”
思路:
1.根据数据源创建字符输入流对象
2.根据目的地创建字符输出流对象
3.读写数据,复制文件
4.释放资源
import java.io.*;
public class CopyJavaDemo01 {
public static void main(String[] args) throws IOException {
//1.根据数据源创建字符输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("myIO\\ConversionStreamDemo.java"));
//2.根据目的地创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myIO\\Copy.java"));
//3.读写数据,复制文件
int ch;
while ((ch=isr.read())!=-1){
osw.write(ch);
}
char[] chs = new char[1024];
int len;
while ((len=isr.read(chs))!=-1){
osw.write(chs,0,len);
}
//4.释放资源
isr.close();
osw.close();
}
}
改进版:
思路:
1.根据数据源创建字符输入流对象
2.根据目的地创建字符输出流对象
3.读写数据,复制文件
4.释放资源
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyJavaDemo02 {
public static void main(String[] args) throws IOException {
//1.根据数据源创建字符输入流对象
FileReader fr = new FileReader("myIO\\ConversionStreamDemo.java");
//2.根据目的地创建字符输出流对象
FileWriter fw = new FileWriter("myIO\\Copy.java");
//3.读写数据,复制文件
int ch;
while ((ch= fr.read())!=-1){
fw.write(ch);
}
char[] chs = new char[1024];
int len;
while ((len=fr.read(chs))!=-1){
fw.write(chs,0,len);
}
//4.释放资源
fr.close();
fw.close();
}
}
7.字符缓冲流
字符缓冲流:
BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途。
BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。
构造方法:
BufferedWriter(Writer out)
BufferedReader(Reader in)
import java.io.*;
public class BufferedStreamDemo01 {
public static void main(String[] args) throws IOException {
//BufferedWriter(Writer out)
/*FileWriter fw = new FileWriter("myIO\\bw.txt");
BufferedWriter bw = new BufferedWriter(fw);
bw.write("hello\n");
bw.write("world");
bw.close();*/
//BufferedReader(Reader in)
BufferedReader br = new BufferedReader(new FileReader("myIO\\bw.txt"));
// int ch;
// while ((ch=br.read())!=-1){
// System.out.print((char)ch);
// }
char[] chs = new char[1024];
int len;
while ((len=br.read(chs))!=-1){
System.out.print(new String(chs,0,len));
}
br.close();
}
}
案例:复制Java文件(字符缓冲流改进版)
import java.io.*;
public class CopyJavaDemo01 {
public static void main(String[] args) throws IOException {
//创建字符缓冲流输入流对象
FileReader fr = new FileReader("myIO\\ConversionStreamDemo.java");
BufferedReader br = new BufferedReader(fr);
//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("myIO\\Copy.java"));
//读写数据,复制文件
int ch;
while ((ch=br.read())!=-1){
bw.write(ch);
}
char[] chs = new char[1024];
int len;
while ((len=br.read(chs))!=-1){
bw.write(chs,0,len);
}
br.close();
bw.close();
}
}
8.字符缓冲流特有功能
BufferedWriter:void newLine():写一行行分隔符,行分隔符字符串由系统属性定义
BufferedReader:public String readLine():读一行文字。结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾已经到达,则为null。
import java.io.*;
public class BufferedStreamDemo02 {
public static void main(String[] args) throws IOException {
//创建字符缓冲输出流对象
/* BufferedWriter bw = new BufferedWriter(new FileWriter("myIO\\bw.txt"));
//写数据
for (int i = 0; i < 10; i++) {
bw.write("hello" + i);
// bw.write("\r\n");
bw.newLine();
bw.flush();
}
bw.close();
*/
BufferedReader br = new BufferedReader(new FileReader("myIO\\bw.txt"));
/*//一次读一行
String line = br.readLine();
System.out.println(line);
line = br.readLine();
System.out.println(line);*/
String line;
while ((line=br.readLine())!=null){
System.out.println(line);
}
br.close();
}
}
案例:复制Java文件(字符缓冲流特有功能改进版)
import java.io.*;
public class CopyJavaDemo02 {
public static void main(String[] args) throws IOException {
//输入流
BufferedReader br = new BufferedReader(new FileReader("myIO\\ConversionStreamDemo.java"));
//输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("myIO\\Copy.java"));
//读写数据,复制文件
String line;
while ((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//释放资源
br.close();
bw.close();
}
}
9.IO流小结
注:字节流可以复制任意文件数据,有4种方式一般采用字节缓冲流一次读写一个字节数组的方式。
注:字符流只能复制文本数据,有5种方式,一般采用字符缓冲流的特有功能
案例:集合到文件
需求:把ArrayList集合中的字符串数据写入到文本文件。要求:每一个字符串元素作为文件中的一行数据。
思路:
1.创建ArrayList集合
2.往集合中存储字符串元素
3.创建字符缓冲输出流对象
4.遍历集合,得到每一个字符串数据
5.调用字符缓冲输出流对象的方法写数据
6.释放资源
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
public class ArrayListToTxtDemo {
public static void main(String[] args) throws IOException {
//1.创建ArrayList集合
ArrayList<String> array = new ArrayList<>();
//2.往集合中存储字符串元素
array.add("hello");
array.add("world");
array.add("java");
//3.创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("myIO\\array.txt"));
//4.遍历集合,得到每一个字符串数据
for (String s : array) {
//5.调用字符缓冲输出流对象的方法写数据
bw.write(s);
bw.newLine();
bw.flush();
}
//6.释放资源
bw.close();
}
}
案例:文件到集合
需求:把文本文件中的数据读取到集合中,并遍历集合。要求:文件中每一行数据是一个集合元素。
思路:
1.创建字符缓冲输入流对象
2.创建ArrayList集合
3.调用字符缓冲输入流对象的方法读数据
4.把读取到的字符串数据存储到集合中
5.释放资源
6.遍历集合
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
public class TxtToArrayListDemo {
public static void main(String[] args) throws IOException {
//1.创建字符缓冲输出流对象
BufferedReader br = new BufferedReader(new FileReader("myIO\\array.txt"));
//2.创建ArrayList集合
ArrayList<String> array = new ArrayList<>();
//3.调用字符缓冲输入流对象的方法读数据
String line;
while ((line = br.readLine()) != null) {
//4.把读取到的字符串数据存储到集合中
array.add(line);
}
//5.释放资源
br.close();
//6.遍历集合
for (String s : array) {
System.out.println(s);
}
}
}
案例:点名器
需求:有一个文件里面存储了班级同学的姓名,每一个姓名占一行,要求通过程序实现随机点名器
思路:
1.创建字符缓冲输入流对象
2.创建ArrayList集合对象
3.调用字符缓冲输入流对象的方法读数据
4.把读取到的字符串数据存储到集合中
5.释放资源
6.使用Random产生一个随机数,随机数的范围在:[0,集合长度)
7.把第6步产生的随机数作为索引到ArrayList集合中获取值
8.把第7步得到的数据输出在控制台
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
public class CallNameDemo {
public static void main(String[] args) throws IOException {
//1.创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("myIO\\names.txt"));
//2.创建ArrayList集合对象
ArrayList<String> array = new ArrayList<>();
//3.调用字符缓冲输入流对象的方法读数据
String line;
while ((line = br.readLine()) != null) {
//4.把读取到的字符串数据存储到集合中
array.add(line);
}
//5.释放资源
br.close();
//6.使用Random产生一个随机数,随机数的范围在:[0,集合长度)
Random r = new Random();
int index = r.nextInt(array.size());
//7.把第6步产生的随机数作为索引到ArrayList集合中获取值
String name = array.get(index);
//8.把第7步得到的数据输出在控制台
System.out.println("幸运者是:" + name);
}
}
案例:集合到文件(改进版)
需求:把ArrayList集合中的学生数据写入到文本文件。要求:每一个学生对象的数据作为文件中的一行数据
格式:学号,姓名,年龄,居住地 例:001,路飞,23,郑州
思路:
1.定义学生类
2.创建ArrayList集合
3.创建学生对象
4.把学生对象添加到集合中
5.创建字符缓冲输出流对象
6.遍历集合,得到每一个学生对象
7.把学生对象的数据拼接成指定格式的字符串
8.调用字符缓冲输出流对象的方法写数据
9.释放资源
/*
学生类
*/
public class Student {
private String sid;
private String name;
private int age;
private String address;
public Student() {
}
public Student(String sid, String name, int age, String address) {
this.sid = sid;
this.name = name;
this.age = age;
this.address = address;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
public class ArrayListToFileDemo {
public static void main(String[] args) throws IOException {
//2.创建ArrayList集合
ArrayList<Student> array = new ArrayList<>();
//3.创建学生对象
Student s1 = new Student("001", "路飞", 20, "郑州");
Student s2 = new Student("002", "萨博", 25, "西安");
Student s3 = new Student("003", "艾斯", 28, "北京");
Student s4 = new Student("004", "索隆", 22, "武汉");
//4.把学生对象添加到集合中
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);
//5.创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(newFileWriter("myIO\\src\\CharStream_06\\student.txt"));
//6.遍历集合,得到每一个学生对象
for (Student s : array) {
//7.把学生对象的数据拼接成指定格式的字符串
StringBuilder sb = new StringBuilder();
sb.append(s.getSid()).append(",").append(s.getName()).append(",").append(s.getAge()).append(",").append(s.getAddress());
//8.调用字符缓冲输出流对象的方法写数据
bw.write(sb.toString());
bw.newLine();
bw.flush();
}
//9.释放资源
bw.close();
}
}
案例:文件到集合(改进版)
需求:把文本文件中的数据读取到集合中,并遍历集合。要求:文件中每一行数据是一个学生对象的成员变量值。例:001,路飞,23,郑州
思路:
1.定义学生类
2.创建字符缓冲输入流对象
3.创建ArrayList集合对象
4.调用字符缓冲输入流对象的方法读数据
5.把读取到的字符串数据用split()进行分隔,得到一个字符串数组
6.创建学生对象
7.把字符串数组中的每一个元素取出来对应的赋值给学生对象的成员变量值
8.把学生对象添加到集合
9.释放资源
10.遍历集合
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
public class FileToArrayListDemo {
public static void main(String[] args) throws IOException {
//2.创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("myIO\\src\\CharStream_06\\student.txt"));
//3.创建ArrayList集合对象
ArrayList<Student> array = new ArrayList<>();
//4.调用字符缓冲输入流对象的方法读数据
String line;
while ((line = br.readLine()) != null) {
//5.把读取到的字符串数据用split()进行分隔,得到一个字符串数组
String[] strArray = line.split(",");
//6.创建学生对象
Student s = new Student();
//7.把字符串数组中的每一个元素取出来对应的赋值给学生对象的成员变量值
s.setSid(strArray[0]);
s.setName(strArray[1]);
s.setAge(Integer.parseInt(strArray[2]));
s.setAddress(strArray[3]);
//8.把学生对象添加到集合
array.add(s);
}
//9.释放资源
br.close();
//10.遍历集合
for (Student s : array) {
System.out.println(s.getSid() + "," + s.getName() + "," + s.getAge() + "," + s.getAddress());
}
}
}
案例:集合到文件(数据排序改进版)
需求:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩)。要求按照成绩总分从高到低写入文本文件
格式:姓名,语文成绩,数学成绩,英语成绩 例:路飞,95,92,96
思路:
1.定义学生类
2.创建TreeSet集合,通过比较器排序进行排序
3.键盘录入学生数据
4.创建学生对象,把键盘录入的数据对应赋值给学生对象的成员变量
5.把学生对象添加到TreeSet集合
6.创建字符缓冲输出流对象
7.遍历集合,得到每一个学生对象
8.把学生对象的数据拼接成指定格式的字符串
9.调用字符缓冲输出流对象的方法写数据
10.释放资源
/*
学生类 :姓名,语文成绩,数学成绩,英语成绩
*/
public class Student {
private String name;
private int chinese;
private int math;
private int english;
public Student() {
}
public Student(String name, int chinese, int math, int english) {
this.name = name;
this.chinese = chinese;
this.math = math;
this.english = english;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getChinese() {
return chinese;
}
public void setChinese(int chinese) {
this.chinese = chinese;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getEnglish() {
return english;
}
public void setEnglish(int english) {
this.english = english;
}
public int getSum() {
return this.chinese + this.math + this.english;
}
}
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;
public class TreeSetToFileDemo {
public static void main(String[] args) throws IOException {
//2.创建TreeSet集合,通过比较器排序进行排序
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//按照总分从高到低
int num = s2.getSum() - s1.getSum();
//次要条件
int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;
int num4 = num3 == 0 ? s1.getName().compareTo(s2.getName()) : num3;
return num4;
}
});
//3.键盘录入学生数据
for (int i = 0; i < 5; i++) {
Scanner sc = new Scanner(System.in);
System.out.println("请录入第" + (i + 1) + "个学生信息:");
System.out.println("姓名:");
String name = sc.nextLine();
System.out.println("语文成绩:");
int chinese = sc.nextInt();
System.out.println("数学成绩:");
int math = sc.nextInt();
System.out.println("英语成绩:");
int english = sc.nextInt();
//4.创建学生对象,把键盘录入的数据对应赋值给学生对象的成员变量
Student s = new Student();
s.setName(name);
s.setChinese(chinese);
s.setMath(math);
s.setEnglish(english);
//5.把学生对象添加到TreeSet集合
ts.add(s);
}
//6.创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("myIO\\src\\CharStream_07\\ts.txt"));
//7.遍历集合,得到每一个学生对象
for (Student s : ts) {
//8.把学生对象的数据拼接成指定格式的字符串
StringBuilder sb = new StringBuilder();
//姓名,语文成绩,数学成绩,英语成绩
sb.append(s.getName()).append(",").append(s.getChinese()).append(",").append(s.getMath()).append(",").append(s.getEnglish()).append(",").append(s.getSum());
//9.调用字符缓冲输出流对象的方法写数据
bw.write(sb.toString());
bw.newLine();
bw.flush();
}
//10.释放资源
bw.close();
}
}
案例:复制单级文件夹
需求:把“E:\itcast ”文件夹复制到模块目录下。
思路:
1.创建数据源目录File对象,路径是E:\itcast
2.获取数据源目录File对象的名称(itcast)
3.创建目的地目录File对象,路径名是模块名 + itcast组成
4.判断目的地目录对应的File是否存在,如果不存在就创建
5.获取数据源目录下所有文件的File数组
6.遍历File数组,得到每一个File对象,该File对象,其实就是数据源文件;
数据源文件:E:\itcast\mn.jpg
7.获取数据源文件File对象的名称(mn.jpg)
8.创建目的地文件File对象,路径名是目的地目录 + mn.jpg组成
9.复制文件
由于文件不仅仅是文本文件,还有图片,视频等文件,所以采用字节流复制文件
import java.io.*;
public class CopyFolderDemo {
public static void main(String[] args) throws IOException {
//1.创建数据源目录File对象,路径是E:\\itcast
File srcFolder = new File("E:\\itcast");
//2.获取数据源目录File对象的名称(itcast)
String srcFolderName = srcFolder.getName();
//3.创建目的地目录File对象,路径名是模块名 + itcast组成
File destFolder = new File("myIO",srcFolderName);
//4.判断目的地目录对应的File是否存在,如果不存在就创建
if(!destFolder.exists()){
destFolder.mkdir();
}
//5.获取数据源目录下所有文件的File数组
File[] listFiles = srcFolder.listFiles();
//6.遍历File数组,得到每一个File对象,该File对象,其实就是数据源文件;
for (File srcFile:listFiles){
//数据源文件:E:\\itcast\\mn.jpg
//7.获取数据源文件File对象的名称(mn.jpg)
String srcFileName = srcFile.getName();
//8.创建目的地文件File对象,路径名是目的地目录 + mn.jpg组成
File destFile = new File(destFolder,srcFileName);
//9.复制文件
copyFile(srcFile,destFile);
}
}
private static void copyFile(File srcFile, File destFile) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
byte[] bys = new byte[1024];
int len;
while ((len=bis.read(bys))!=-1){
bos.write(bys,0,len);
}
bos.close();
bis.close();
}
}
案例:复制多级文件夹
需求:把“E:\itcast ”文件夹复制到D盘目录下。
思路:
1.创建数据源File对象,路径是E:\itcast
2.创建目的地File对象,路径名D:\
3.写方法实现文件夹的复制,参数为数据源File对象的目的地File对象
4.判断数据源File是否是目录,是:
A:在目的地下创建和数据源File名称一样的目录
B:获取数据源File所有文件或者目录的File数组
C:遍历该File数组,得到每一个File对象
D:把该File作为数据源File对象,递归调用复制文件夹的方法
不是:说明是文件,直接复制,用字节流
import java.io.*;
public class CopyFoldersDemo {
public static void main(String[] args) throws IOException {
//1.创建数据源File对象,路径是E:\\itcast
File srcFile = new File("E:\\");
//2.创建目的地File对象,路径名D:\\
File destFile = new File("D:\\");
//3.写方法实现文件夹的复制,参数为数据源File对象的目的地File对象
copyFolder(srcFile,destFile);
}
//复制文件夹
private static void copyFolder(File srcFile, File destFile) throws IOException {
//判断数据源File是否是目录
if(srcFile.isDirectory()){
// A:在目的地下创建和数据源File名称一样的目录
String srcFileName = srcFile.getName();
File newFolder = new File(destFile,srcFileName);
if(!newFolder.exists()){
newFolder.mkdir();
}
// B:获取数据源File所有文件或者目录的File数组
File[] fileArray = srcFile.listFiles();
// C:遍历该File数组,得到每一个File对象
for (File file:fileArray){
// D:把该File作为数据源File对象,递归调用复制文件夹的方法
copyFolder(file,newFolder);
}
} else{
// 不是:说明是文件,直接复制,用字节流
File newFile = new File(destFile,srcFile.getName());
copyFile(srcFile,newFile);
}
}
//字节缓冲流复制文件
private static void copyFile(File srcFile, File destFile) throws IOException{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
byte[] bys = new byte[1024];
int len;
while ((len=bis.read(bys))!=-1){
bos.write(bys,0,len);
}
bos.close();
bis.close();
}
}
10.复制文件的异常处理
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyFileDemo {
public static void main(String[] args) {
}
//JDK9的改进方案
private static void method4() throws IOException {
FileReader fr = new FileReader("fr.txt");
FileWriter fw = new FileWriter("fw.txt");
try(fr;fw) {
char[] chs = new char[1024];
int len;
while ((len = fr.read()) != -1) {
fw.write(chs, 0, len);
}
}catch (IOException e){
e.printStackTrace();
}
}
//JDK7的改进方案
private static void method3() {
try(FileReader fr = new FileReader("fr.txt");
FileWriter fw = new FileWriter("fw.txt");) {
char[] chs = new char[1024];
int len;
while ((len = fr.read()) != -1) {
fw.write(chs, 0, len);
}
}catch (IOException e){
e.printStackTrace();
}
}
//try...catch...finally
private static void method2() {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("fr.txt");
fw = new FileWriter("fw.txt");
char[] chs = new char[1024];
int len;
while ((len = fr.read()) != -1) {
fw.write(chs, 0, len);
}
}catch (IOException e){
e.printStackTrace();
}finally{
if(fr!=null){
try{
fr.close();
}catch (IOException e){
e.printStackTrace();
}
}
if(fw!=null){
try {
fw.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
//复制文本文件 抛出异常
private static void method1() throws IOException {
FileReader fr = new FileReader("fr.txt");
FileWriter fw = new FileWriter("fw.txt");
char[] chs = new char[1024];
int len;
while ((len = fr.read())!=-1){
fw.write(chs,0,len);
}
fr.close();
fw.close();
}
}
4.特殊操作流
1.标准输入输出流
System类中有两个静态的成员变量:
public static final InputStream in:“标准”输入流。通常,该流对应于键盘输入或由主机环境或用户指定的另一个输入源。
public static final PrintStream out:“标准”输出流。通常,此流对应于显示输出或由主机环境或用户指定的另一个输出目标。
自己实现键盘录入:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Java类实现键盘录入:Scanner sc = new Scanner(System.in);
import java.io.BufferedReader;
import java.io.IOException;
//import java.io.InputStream;
import java.io.InputStreamReader;
public class SystemInDemo {
public static void main(String[] args) throws IOException {
/*//public static final InputStream in: “标准”输入流
InputStream is = System.in;
int by;
while ((by=is.read())!=-1){
System.out.print((char)by);
}
//把字节流转换为字符流方法: 转换流
InputStreamReader isr = new InputStreamReader(is);
//使用字符流能不能够实现一次读取一行数据? 可以
//但是,一次读取一行数据的方法是字符缓冲输入流的特有方法
BufferedReader br = new BufferedReader(isr);*/
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入一个字符串:");
String line = br.readLine();
System.out.println("你输入的字符串是:" + line);
System.out.println("请输入一个整数:");
int i = Integer.parseInt(br.readLine());
System.out.println("你输入的整数是:" + i);
}
}
输出语句的本质:是一个标准的输出流
PrintStream ps = System.out;
PrintStream类有的方法,System.out都可以使用
import java.io.PrintStream;
public class SystemOutDemo {
public static void main(String[] args) {
//public static final PrintStream out:“标准”输出流
PrintStream ps = System.out;
//能够方便地打印各种数据值
ps.println("hello");
ps.println(100);
//System.out的本质是一个字节输出流
System.out.println(123);
}
}
2.打印流
打印流分类:
字节打印流:PrintStream
字符打印流:PrintWriter
打印流的特点:只负责输出数据,不负责读取数据;有自己的特有方法
字节打印流:
PrintStream(String fileName) :使用指定的文件名创建新的打印流
使用继承父类的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出
import java.io.IOException;
import java.io.PrintStream;
public class PrintStreamDemo {
public static void main(String[] args) throws IOException {
PrintStream ps = new PrintStream("myIO\\src\\OtherStream_02\\ps.txt");
//写数据
//字节输出流的方法
ps.write(97); //a
//特有方法
ps.println(97); //97
ps.print(98);
ps.close();
}
}
方法名 | 说明 |
---|---|
PrintWriter(String fileName) | 使用指定的文件名创建一个新的PrintWriter,而不需要自动执行行刷新。 |
PrintWriter(Writer out, boolean autoFlush) | 创建一个新的PrintWriter;out - 字符输出流 ;autoFlush - 一个布尔值 如果为真,则println , printf ,或format方法将刷新输出缓冲区 |
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class PrintWriterDemo {
public static void main(String[] args) throws IOException {
/*PrintWriter pw = new PrintWriter("myIO\\src\\OtherStream_02\\ps.txt");
pw.write("hello");
pw.write("\r\n");
pw.flush();
pw.println("hello");
pw.flush();
pw.println("world");
pw.flush();*/
//自动刷新
PrintWriter pw = new PrintWriter(new FileWriter("myIO\\src\\OtherStream_02\\ps.txt"),true);
pw.println("hello");
pw.println("world");
pw.close();
}
}
案例:复制Java文件(打印流改进版)
需求:把模块目录下的PrintStreamDemo.java复制到模块目录下的Copy.java
思路:
1.根据数据源创建字符输入流对象
2.根据目的地创建字符输出流对象
3.读写数据,复制文件
4.释放资源
import java.io.*;
public class CopyJavaDemo {
public static void main(String[] args) throws IOException {
/*
//1.根据数据源创建字符输入流对象
BufferedReader br = new BufferedReader(new FileReader("myIO\\src\\OtherStream_02\\PrintStreamDemo.java"));
//2.根据目的地创建字符输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("myIO\\src\\OtherStream_02\\Copy.java"));
//3.读写数据,复制文件
String line;
while ((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//4.释放资源
br.close();
bw.close();
*/
BufferedReader br = new BufferedReader(new FileReader("myIO\\src\\OtherStream_02\\PrintStreamDemo.java"));
//根据目的地创建字符输出流对象
PrintWriter pw = new PrintWriter(new PrintWriter("myIO\\src\\OtherStream_02\\Copy.java"),true);
//读写数据,复制文件
String line;
while ((line=br.readLine())!=null){
pw.println(line);
}
pw.close();
br.close();
}
}
3.对象序列化流
对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象
这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息
字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
要实现序列化和反序列化就要使用对象序列化流和对象反序列化流:
对象序列化流:ObjectOutputStream
对象反序列化流:ObjectInputStream
对象序列化流:ObjectOutputStream
将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象。
构造方法:ObjectOutputStream(OutputStream out) 创建一个写入指定的OutputStream的ObjectOutputStream。
序列化对象方法:void writeObject(Object obj) 将指定的对象写入ObjectOutputStream。
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/*
NotSerializableException:抛出一个实例需要一个Serializable接口。 序列化运行时或实例的类可能会抛出此异常
类的序列化由实现java.io.Serializable接口的类启用。 不实现此接口的类将不会使任何状态序列化或反序列化。
*/
public class ObjectOutputStreamDemo {
public static void main(String[] args) throws IOException {
//构造方法
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myIO\\src\\OtherStream_03\\oos.txt"));
//创建对象
Student s = new Student("路飞",23);
//void writeObject(Object obj) 将指定的对象写入ObjectOutputStream
oos.writeObject(s);
oos.close();
}
}
注:一个对象要想被序列化,该对象所属的类必须实现Serializable接口;Serializable是一个标记接口,实现该接口,不需要重写任何方法
对象反序列化流:ObjectInputStream
ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象。
构造方法:
ObjectInputStream(InputStream in) 创建从指定的InputStream读取的ObjectInputStream。
反序列化对象的方法:
Object readObject() :从ObjectInputStream读取一个对象。
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ObjectInputStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myIO\\src\\OtherStream_03\\oos.txt"));
Object obj = ois.readObject();
Student s = (Student) obj; //向下转型
System.out.println(s.getName() + "," + s.getAge());
ois.close();
}
}
4.Properties
概述:
是一个Map体系的集合类
Properties可以保存到流中或从流中加载
练习:Properties作为Map集合的使用
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo01 {
public static void main(String[] args) {
//创建集合对象
Properties prop = new Properties();
//存储元素
prop.put("路飞", 23);
prop.put("艾斯", 28);
prop.put("萨博", 26);
//遍历集合
Set<Object> keySet = prop.keySet();
for (Object key : keySet) {
Object value = prop.get(key);
System.out.println(key + "," + value);
}
}
}
Properties作为集合的特有方法:
方法名 | 说明 |
---|---|
Object setProperty(String key, String value) | 设置集合的键和值,都是String类型,底层调用 Hashtable方法 put |
String getProperty(String key) | 使用此属性列表中指定的键搜索属性 |
Set< String > stringPropertyNames() | 从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 |
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo02 {
public static void main(String[] args) {
//创建集合对象
Properties prop = new Properties();
prop.setProperty("001", "路飞");
prop.setProperty("002", "乔巴");
prop.setProperty("003", "乌索普");
//String getProperty(String key) 使用此属性列表中指定的键搜索属性
System.out.println(prop.getProperty("001"));
// System.out.println(prop);
System.out.println("=================");
//Set< String > stringPropertyNames():从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
Set<String> names = prop.stringPropertyNames();
for (String key : names) {
System.out.println(key);
String value = prop.getProperty(key);
System.out.println(key + "," + value);
}
}
}
Properties 和 IO流结合的方法:
方法名 | 说明 |
---|---|
void load(InputStream inStream) | 从输入字节流读取属性列表(键和元素对) |
void load(Reader reader) | 从输入字节流读取属性列表(键和元素对) |
void store(OutputStream out, String comments) | 将此属性列表(键和元素对)写入此 Properties表中,以适合于使用 load(InputStream)方法的格式写入输出字节流 |
void store(Writer writer, String comments) | 将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式写入输出字符流。 |
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class PropertiesDemo03 {
public static void main(String[] args) throws IOException {
//把集合中的数据保存到文件
myStore();
//把集合中的数据加载到集合
myLoad();
}
private static void myLoad() throws IOException {
Properties prop = new Properties();
FileReader fr = new FileReader("myIO\\src\\OtherStream_04\\fw.txt");
prop.load(fr);
fr.close();
System.out.println(prop);
}
private static void myStore() throws IOException {
Properties prop = new Properties();
prop.setProperty("001","路飞");
prop.setProperty("002","萨博");
prop.setProperty("003","艾斯");
FileWriter fw = new FileWriter("myIO\\src\\OtherStream_04\\fw.txt");
prop.store(fw,null);
fw.close();
}
}
案例:游戏次数
需求:请写程序实现猜数字小游戏只能试玩3次,如果还想玩,提示:游戏试玩结束,想玩请充值(www.it.cn)
思路:
1.写一个游戏类,里面有一个猜数字的小游戏
2.写一个测试类,测试类中有main()方法,main()方法中按照下面步骤完成:
A:从文件中读取数据到Properties集合,用load()方法实现
文件已经存在:game.txt
里面有一个数据值:count = 0
B:通过Properties集合获取到玩游戏的次数
C:判断次数是否到达3次
如果到了,给出提示:游戏结束
如果不到3次:玩游戏
次数+1,重新写回文件,用Properties的store()方法实现
import java.util.Random;
import java.util.Scanner;
/*
游戏类 :猜数字小游戏
*/
public class GuessNumber {
private GuessNumber() {
}
public static void start() {
//要完成猜数字的游戏,首先要有一个要猜的数字,使用随机数,范围1-100
Random r = new Random();
int number = r.nextInt(100) + 1;
while (true) {
//使用程序实现猜数字,每次均要输入要猜的数字
Scanner sc = new Scanner(System.in);
System.out.println("请输入要猜的数字:");
int guessNumber = sc.nextInt();
//比较输入的数字和系统产生的数字
if (guessNumber > number) {
System.out.println("你猜的数字" + guessNumber + "大了");
} else if (guessNumber < number) {
System.out.println("你猜的数字" + guessNumber + "小了");
}else {
System.out.println("猜中了!!!");
break;
}
}
}
}
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
/*
测试类
*/
public class PropertiesTest {
public static void main(String[] args) throws IOException {
//A:从文件中读取数据到Properties集合,用load()方法实现
Properties prop = new Properties();
FileReader fr = new FileReader("myIO\\src\\OtherStream_04\\game.txt");
prop.load(fr);
fr.close();
//B:通过Properties集合获取到玩游戏的次数
String count = prop.getProperty("count");
int number = Integer.parseInt(count);
//C:判断次数是否到达3次
if (number >= 3) {
// 如果到了,给出提示:游戏结束
System.out.println("游戏结束");
} else {
// 如果不到3次:玩游戏
GuessNumber.start();
//次数+1,重新写回文件,用Properties的store()方法实现
number++;
prop.setProperty("count", String.valueOf(number));
FileWriter fw = new FileWriter("myIO\\src\\OtherStream_04\\game.txt");
prop.store(fw, null);
fw.close();
}
}
}