文件对大家来说都不陌生:
new File(String pathname)//根据路径创建一个File对象
new File(File parent,String child)//根据父类目录文件+子路径构建
new File(String parent,String child)//根据父类目录+子路径构建
createNewFile//创建新文件
public class FileCreat {
//演示创建文件
//请在E盘下创建文件news1.txt、news2.txt、news3.txt;
//用三种不同的方式创建
public static void main(String[] args) {
}
//方式1 new File(String pathname)
// 根据路径创建一个File对象
// createNewFile 创建新文件
// E:\\news1.txt
@Test
public void creat01() {
String filePath = "E:\\news1.txt";
//这里的file对象,在java中只是一个对象
//只有执行了creatNewFile 方法
// 才会真正的在磁盘创建该文件
File file = new File(filePath);
try {
//创建新文件
file.createNewFile();
//如果没有抛出异常,那么文件创建成功
System.out.println("文件1创建成功");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//方式2 new File(File parent,String child)
// 根据父类目录文件+子路径构建
// createNewFile 创建新文件
// E:\\news2.txt
@Test
public void creat02() {
File parentFile = new File("E:\\");
String fileName = "news2.txt";
//这里的file对象,在java中只是一个对象
//只有执行了creatNewFile 方法
// 才会真正的在磁盘创建该文件
File file = new File(parentFile, fileName);
try {
//创建新文件
file.createNewFile();
System.out.println("文件2创建成功");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//方式3 new File(String parent,String child)
// 根据父类目录+子路径构建
// createNewFile 创建新文件
// E:\\news3.txt
@Test
public void creat03() {
String parentPath = "E:\\";
String fileName = "news3.txt";
//这里的file对象,在java中只是一个对象
//只有执行了creatNewFile 方法
// 才会真正的在磁盘创建该文件
File file = new File(parentPath, fileName);
try {
//创建新文件
file.createNewFile();
System.out.println("文件3创建成功");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
获取文件相关信息的操作
代码演示:
public class FileIMformation {
public static void main(String[] args) {
}
//获取文件信息
@Test
public void info() {
//先创建文件对象
File file = new File("E:\\news1.txt");
//调用想用的方法,得到对应的信息
//1. getName获取文件名字
System.out.println("文件名字 = " + file.getName());
//输出 文件名字 = news1.txt
//2. getAbsolutePath获取绝对路径
System.out.println("文件绝对路径 = " + file.getAbsolutePath());
//输出 文件绝对路径 = E:\news1.txt
//3. getParent获取文件父级目录
System.out.println("文件父级目录 = " + file.getParent());
//输出 文件父级目录 = E:\
//4. length文件大小(字节)
System.out.println("文件大小(字节) = " + file.length());
//输出 文件大小(字节) = 10
//5. exists文件是否存在
System.out.println("文件是否存在 = " + file.exists());
//输出 文件是否存在 = true
//6. isFile是不是一个文件
System.out.println("是不是一个文件 = " + file.isFile());
//输出 是不是一个文件 = true
//7. isDirectory是不是一个目录
System.out.println("是不是一个目录 = " + file.isDirectory());
//输出 是不是一个目录 = false
}
}
public class Directory_ {
public static void main(String[] args) {
}
//1. 判断 E:\\news1.txt文件是否存在,
// 如果存在就删除
@Test
public void m1() {
String filePath = "E:\\news1.txt";
File file = new File(filePath);
if (file.exists()) {//是否存在
//如果存在,删除文件
if (file.delete()) {//布尔值
System.out.println(filePath + "删除成功");
} else {
System.out.println(filePath + "删除失败");
}
} else {
System.out.println("该文件不存在");
}
}
//2. 判断 E:\\demo02 是否存在,存在就删除,否则提示不存在.
@Test
public void m2() {
String filePath = "E:\\demo02";
File file = new File(filePath);
if (file.exists()) {//是否存在
//如果存在,删除文件
if (file.delete()) {//布尔值
System.out.println(filePath + "删除成功");
} else {
System.out.println(filePath + "删除失败");
}
} else {
System.out.println("该文件不存在");
}
}
//3. 判断 E:\\demo\\a\\b\\c 目录是否存在,如果存在就提示已经存在,否则就创建
@Test
public void m3() {
String directoryPath = "E:\\demo\\a\\b\\c";
File file = new File(directoryPath);
if (file.exists()) {//是否存在
System.out.println(directoryPath + "存在");
} else {
//mkdir创建一级目录
//mkdirs创建多级目录
if (file.mkdirs()) {
System.out.println("创建成功");
} else {
System.out.println("创建失败");
}
}
}
}
这里举个例子说明一下文件和流的关系:
FileInputStream应用实例:
public class FileInputStream_ {
//演示FileInputStream的使用
//字节输入流:文件 --> 程序
//使用read()单个字节的读取,效率比较低
//优化:使用read(byte[] b)读取文件,提高效率
public static void main(String[] args) {
}
/**
* 使用read()单个字节的读取,效率比较低
*/
@Test
public void readFile01() {
String filePath = "E:\\hello.txt";
//创建一个read用于接收
int readDate = 0;
//创建 FileInputStream对象,用于读取文件
FileInputStream fileInputStream = null;
try {
//创建 FileInputStream对象,用于读取文件
fileInputStream = new FileInputStream(filePath);
//从该输入流读取一个字节的数据。 如果没有输入可用,此方法将阻止。
//数据的下一个字节,如果达到文件的末尾,返回 -1 。
//因为内容肯定不止一个,所以我们用while循环
while ((readDate = fileInputStream.read()) != -1) {
System.out.println((char) readDate);//转换成char显示
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//关闭文件,释放资源
//因为FileInputStream在上面的try块中,导致finally中无法捕获到
//所以把FileInputStream对象提取到外面
//这时fileInputStream.close();报异常了
//所以在里面再次try-catch捕获异常
try {
fileInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* 优化:使用read(byte[] b)读取文件,提高效率
*/
@Test
public void readFile02() {
String filePath = "E:\\hello.txt";
//创建一个read用于接收
int readDate = 0;
//先定义一个字节数组
byte[] buf = new byte[8];//一次读取8个字节
int readLen = 0;
//创建 FileInputStream对象,用于读取文件
FileInputStream fileInputStream = null;
try {
//创建 FileInputStream对象,用于读取文件
fileInputStream = new FileInputStream(filePath);
//从该输入流读取最多b.length字节的数据到字节数组。 此方法将阻塞,直到某些输入可用。
//读入缓冲区的总字节数,如果没有更多的数据,因为文件的结尾已经到达, -1 。
//如果读取正常,返回实际读取的字节数
while ((readLen = fileInputStream.read(buf)) != -1) {
System.out.println(new String(buf, 0, readLen));
//输出 hello,wo
// rld
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//关闭文件,释放资源
//因为FileInputStream在上面的try块中,导致finally中无法捕获到
//所以把FileInputStream对象提取到外面
//这时fileInputStream.close();报异常了
//所以在里面再次try-catch捕获异常
try {
fileInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
FileOutputStream应用实例一:
public class FileOutputStream01 {
//演示使用FileOutputStream在a.txt文件中写入"hello,world"
//注意:如果文件不存在,他会自动创建文件(前提:目录已经存在)
public static void main(String[] args) {
}
@Test
public void writeFile() {
String filePath = "E:\\a.txt";
//创建 FileOutputStream 对象
FileOutputStream fileOutputStream = null;
try {
//得到 FileOutputStream 对象
//1. 当是 new FileOutputStream(filePath) 创建方式
// 后面写入的内容将会覆盖原先的内容
//2. 当是 new FileOutputStream(filePath,true) 创建方式
// 后面写入的内容将被写入文件的末尾而不是开头,即不会被覆盖
// append - 如果 true ,则字节将被写入文件的末尾而不是开头
fileOutputStream = new FileOutputStream(filePath);
/*方法一:写入一个字节
//fileOutputStream.write('h');
*/
/*方法二:写入字符串
String str = "hello,world";
//str.getBytes()方法可以把一个字符串转成字节数组
fileOutputStream.write(str.getBytes());
*/
//方法三:write(byte[] b, int off, int len)
//将 len字节从位于偏移量 off的指定字节数组写入此文件输出流。
String str = "hi,world";
fileOutputStream.write(str.getBytes(), 0, str.length());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
FileOutputStream应用实例二:
public class FileCopy {
//完成文件拷贝
public static void main(String[] args) {
//将 E:\\java.png 拷贝到 C:\\
//思路分析
//1. 创建文件输入流,将文件读入到程序中
//2. 创建文件输出流,将读取到的文件数据,写入指定的文件
String srcFilePath = "E:\\java.png";
String finalFilePath = "E:\\java2.png";
//分别创建FileInputStream、FileOutputStream对象并初始化
//用于finally中IO流的关闭
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
fileInputStream = new FileInputStream(srcFilePath);
fileOutputStream = new FileOutputStream(finalFilePath);
//定义一个字节数组
//一次性读取1024字节
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = fileInputStream.read(buf)) != -1) {
fileOutputStream.write(buf, 0, readLen);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
//关闭文件,释放资源
fileInputStream.close();
fileOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
new FileReader(File/String)
read:每次读取单个字符,返回该字符,如果到文件未尾返回-1
read(char[]): 批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1
相关API:
1)new String(char[]):将char[]转换成String
2)new String(char[],off,len):将char[]的指定部分转换成String
案例一:
public class FileReader01 {
public static void main(String[] args) {
}
@Test
public void readFile01() {
String filePath = "E:\\story.txt";
FileReader fileReader = null;
int data = 0;
//1. 创建一个FileReader对象
try {
fileReader = new FileReader(filePath);
//读取
//方法一:
//read:每次读取单个字符,返回该字符,
// 如果到文件未尾返回-1
while ((data = fileReader.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
/*
使用字符数组来读取文件
*/
@Test
public void readFile02() {
String filePath = "E:\\story.txt";
FileReader fileReader = null;
int readLen = 0;
char[] buf = new char[1024];
//1. 创建一个FileReader对象
try {
fileReader = new FileReader(filePath);
//读取
//方法二:
//read(char[]): 批量读取多个字符到数组,返回读取到的字符数,
// 如果到文件末尾返回-1
while ((readLen = fileReader.read(buf)) != -1) {
System.out.print(new String(buf, 0, readLen));
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
案例二:
public class FileWriter01 {
//使用 FileWriter 将 “风雨之后,定见彩虹” 写入到 note.txt 文件中, 注意细节.
public static void main(String[] args) {
String filePath = "E:\\note.txt";
//1. 创建FileWriter对象
FileWriter fileWriter = null;
char[] buf = {'a', 'b', 'c'};
try {
fileWriter = new FileWriter(filePath);
//1. write(int):写入单个字符
fileWriter.write('h');
//2. write(char[]):写入指定数组
fileWriter.write(buf);
//3. write(char[],off,len):写入指定数组的指定部分
// toCharArray:将String转换成char[]
fileWriter.write("加油,努力...".toCharArray(), 0, 5);
//4. write (string) : 写入整个字符串
fileWriter.write("sys学java");
fileWriter.write("风雨之后,定见彩虹");
//5. write(string,off,len):写入字符串的指定部分
fileWriter.write("我要变得更强,勇攀高峰", 0, 6);
//在数据量大的情况下可以使用循环结构
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//注意细节:
//FileWriter使用后,必须要关闭(close)或刷新(flush),
// 否则写入不到指定的文件!
if (fileWriter != null) {
try {
/*源码阅读:为什么必须要关闭(close)或刷新(flush)
private void writeBytes() throws IOException {
this.bb.flip();
int var1 = this.bb.limit();
int var2 = this.bb.position();
assert var2 <= var1;
int var3 = var2 <= var1 ? var1 - var2 : 0;
if (var3 > 0) {
if (this.ch != null) {
assert this.ch.write(this.bb) == var3 : var3;
} else {
this.out.write(this.bb.array(), this.bb.arrayOffset() + var2, var3);
}
}
this.bb.clear();
}
*/
//fileWriter.flush();
//关闭文件流,等价于flush()+关闭;
fileWriter.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
节点流可以从一个特定的数据源读写数据,如FileReader、FileWriter [源码]
处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,也更加灵活,如BufferedReader、BufferedWriter
BufferedReader类中,有属性Reader,即可以封装一个节点流,该节点流是可以任意的,只要是Reader的子类
源码
public class BufferedReader extends Reader {
private Reader in;
private char cb[];
BufferedWriter类中,有属性Writer,即可以封装一个节点流,该节点流是可以任意的,只要是Writer的子类
源码
public class BufferedWriter extends Writer {
private Writer out;
private char cb[];
节点流是底层流/低级流,直接跟数据源相接。
处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。[源码理解]
处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连[模拟修饰器设计模式]
下面简单的模拟一下修饰器设计模式
先定义一个抽象类Reader_.java
public abstract class Reader_ {
//让FileReader实现
public void readFile() {
}
//让StringReader实现
public void readString() {
}
}
然后定义两个实现他的类
public class FileReader_ extends Reader_{
//字节流
//对文件进行读取 FileReader_
public void readFile(){
System.out.println("对文件进行读取...");
}
}
public class StringReader_ extends Reader_{
//字节流
//对字符串进行读取 StringReader_
public void readString(){
System.out.println("对字符串进行读取...");
}
}
定义一个处理流(包装流) BufferReader_
public class BufferReader_ {
//做成处理流(包装流)
//属性是Reader_类型
private Reader_ reader_;
//生成构造器
public BufferReader_(Reader_ reader_) {
this.reader_ = reader_;
}
//如果就只想调用readFile() 方法
//只需要进行封装一次就行
public void readFile() {
reader_.readFile();
}
//让方法更加灵活,创建一个方法
//扩展 readFile
//多次读取文件,或者加缓冲byte[]
public void readFiles(int num) {
for (int i = 0; i < num; i++) {
//可以直接调用 reader_ 的方法
reader_.readFile();
}
}
//扩展 readString ,批量处理字符串数据
public void readStrings(int num) {
for (int i = 0; i < num; i++) {
reader_.readString();
}
}
}
最后创建一个测试类 Test_
public class Test_ {
public static void main(String[] args) {
//希望通过 BufferReader_ 多次读取文件
BufferReader_ bufferReader_1 = new BufferReader_(new FileReader_());
System.out.println("readFile()拓展");
//调用 bufferReader_ 的方法
bufferReader_1.readFiles(5);
System.out.println("readFile()原始方法");
//直接调用最原始的方法readFile()
bufferReader_1.readFile();
//希望通过 BufferReader_ 多次读取字符串
BufferReader_ bufferReader_2 = new BufferReader_(new StringReader_());
System.out.println("readString批量操作");
bufferReader_2.readStrings(5);
}
}
性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便。+
关于上面提到的模拟修饰器设计模式,我们在实际情况下,会使用一个read方法统一管理
把Reader_中的两个方法改成一个read方法
public abstract class Reader_ {
//让FileReader实现
public void readFile() {
}
//让StringReader实现
public void readString() {
}
//在 Reader_ 抽象类,使用read方法统一管理
//在后面调用的时候,利用动态绑定机制,绑定到对应的实现子类
//public abstract void read();
}
然后依次把FileReader_和 StringReader_里面的方法都改为read方法统一管理
BufferedReader 和 BufferedWriter 属于字符流,是按照字符来读取数据的;
关闭时处理流,只需要关闭外层流即可[后面看源码]
即我们关闭处理流(包装流)的时候,底层会自动关闭包装流对应的节点流;
案例应用:
public class BufferedReader_ {
//使用BufferedReader 读取文本文件,并显示在控制台
public static void main(String[] args) throws Exception {
String filePath = "E:\\story.txt";
//创建 bufferedReader
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
//读取
String Line;//按行读取,效率高
//1. bufferedReader.readLine() 是按行读取文件
//2. 当返回null时,表示文件读取完毕
while ((Line = bufferedReader.readLine()) != null) {
System.out.println(Line);
}
//关闭流 这里只要关闭 bufferedReader
//底层就会自动关闭 FileReader
/*
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();//in就是我们传入的new FileReader(filePath)
} finally {
in = null;
cb = null;
}
}
}
*/
bufferedReader.close();
}
}
public class BufferedWriter_ {
//使用BufferedWriter 将”sys学java”,写入到文件中
public static void main(String[] args) throws Exception {
String filePath = "E:\\study.txt";
//创建 bufferedWriter
//new FileWriter(filePath,true)表示以追加的方式写入
//new FileWriter(filePath)表示以覆盖的方式写入
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
bufferedWriter.write("sys学java");
//插入一个和系统相关的换行
//如果有多句话要写入,插入换行会更清晰
bufferedWriter.newLine();
bufferedWriter.write("sys学java中");
//关闭外层流即可,传入的 new FileWriter(filePath)会在底层自动关闭
bufferedWriter.close();
}
}
综合使用BufferedReader 和 BufferedWriter 完成 文本文件拷贝,注意文件编码
代码如下:
public class BufferedCopy_ {
public static void main(String[] args) {
//注意:我们 BufferedReader 和 BufferedWriter是字符流
//不要操作二进制文件,否则可能导致文件的损坏
String filePath1 = "E:\\game1.txt";
String filePath2 = "E:\\game2.txt";
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
try {
bufferedReader = new BufferedReader(new FileReader(filePath1));
bufferedWriter = new BufferedWriter(new FileWriter(filePath2));
String readLine;
while ((readLine = bufferedReader.readLine()) != null) {
bufferedWriter.write(readLine);
// 因为 bufferedReader 是按行读取的
// 所以记得插入换行,要不然复制的文件会全部放在一行
bufferedWriter.newLine();
}
System.out.println("拷贝完毕...");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (bufferedReader != null) {
bufferedReader.close();
}
if (bufferedWriter != null) {
bufferedWriter.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
BufferedInputStream是字节流,
在创建 BufferedInputStream时,会创建一个内部缓冲区数组.
BufferedInputStream构造方法
BufferedInputStream方法摘要
BufferedInputStream类图
BufferedOutputStream是字节流,实现缓冲的输出流,
可以将多个字节写入底层输出流中,而不必对每次字节写入调用底层系统
BufferedOutputStream的构造方法
BufferedOutputStream的方法摘要
BufferedOutputStream类图
public class BufferedCopy02 {
//要求: 编程完成图片/音乐 的拷贝(要求使用Buffered..流)
public static void main(String[] args) {
String srcFilePath = "E:\\java.png";
String destFilePath = "E:\\boo.png";
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
bufferedInputStream = new BufferedInputStream(new FileInputStream(srcFilePath));
bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destFilePath));
//循环读取文件,并写入到 destFilePath
byte[] buf = new byte[1024];
int readLen = 0;
//当返回-1时,表示文件读取完毕
while ((readLen = bufferedInputStream.read(buf)) != -1) {
bufferedOutputStream.write(buf);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
//关闭流
bufferedInputStream.close();
bufferedOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
看以下需求:
序列化和反序列化
序列化就是在保存数据时,保存数据的值和数据类型
反序列化就是在恢复数据时,恢复数据的值和数据类型
需要让某个对象支持序列化机制,则必须让其类是可序列化的,
为了让某个类是可序列化的,该类必须实现如下两个接口之一:
序列化和反序列化示意图
功能:提供了对基本类型或对象类型的序列化和反序列化的方法
ObjectOutputStream 提供 序列化功能
ObjectInputStream 提供 反序列化功能
ObjectInputStream 和ObjectOutputStream类图
案例一:
public class ObjectOutStream {
//使用ObjectOutputStream 序列化 基本数据类型
// 和一个 Dog对象(name,age),并保存到 data.dat 文件中
public static void main(String[] args) throws Exception {
//序列化后保存的文件格式不是纯文本,而是按照他自己的格式来保存
String filePath = "E:\\data.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
//保存数据
//自动装箱
oos.writeInt(100);//int --> Integer(实现了 Serializable)
oos.writeDouble(6.66);//double --> Double(实现了 Serializable)
oos.writeBoolean(true);//boolean --> Boolean(实现了 Serializable)
oos.writeChar('来');//char --> Char(实现了 Serializable)
oos.writeUTF("sys学java");//String (实现了 Serializable)
//保存一个对象
oos.writeObject(new Dog("皮皮"));
}
}
//为了让某个类是可序列化的,该类必须实现如下两个接口之一:
// - Serializable // 这是一个标记接口,没有方法
// - Externalizable // 该接口有方法需要实现,因此我们一般实现上面的 Serializable接口
class Dog implements Serializable {
private String name;
private int age;
public Dog(String name) {
this.name = name;
}
}
案例二:
public class ObjectInputStream_ {
//使用ObjectInputStream 读取 data.dat 并反序列化恢复数据
public static void main(String[] args) throws Exception {
//指定反序列化文件
String filePath = "E:\\data.dat";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
//1. 读取的顺序(反序列化)要跟存放(序列化)的顺序一致
//2. 否则会出现异常
/*刚刚
oos.writeInt(100);//int --> Integer(实现了 Serializable)
oos.writeDouble(6.66);//double --> Double(实现了 Serializable)
oos.writeBoolean(true);//boolean --> Boolean(实现了 Serializable)
oos.writeChar('来');//char --> Char(实现了 Serializable)
oos.writeUTF("sys学java");//String (实现了 Serializable)
oos.writeObject(new Dog("皮皮",4));
*/
System.out.println(ois.readInt());
System.out.println(ois.readDouble());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readUTF());
//System.out.println(ois.readObject());
//也可以像下面那样写
//dog 的编译类型是 Object ,dog 的运行类型是 dog
Object dog = ois.readObject();
System.out.println("dog的运行 =" + dog.getClass());
System.out.println("dog的信息 =" + dog);
//如果我们想要调用Dog的方法,需要向下转型
Dog dog1 = (Dog) dog;
System.out.println(dog1.getName());//皮皮
//关闭流
ois.close();
System.out.println("读取成功...");
}
}
System.in 标准输入 类型:InputStream 默认设备:键盘
System.out 标准输出 类型:OutputStream 默认键盘:显示器
传统方法System.out.println(" ");是使用 out 对象将 数据输出到 显示器
传统的方法,Scanner 是从 标准输入 健盘接收数据
简单代码演示:
public class InputAndOutput {
public static void main(String[] args) {
//1. System类的 public final static InputStream in = null;
//2. System.in 的编译类型是 InputStream
//3. System.in 的运行类型是 BufferedInputStream
//4. 表示标准输入 键盘
System.out.println(System.in.getClass());
//输出 class java.io.BufferedInputStream
//1. System类的 public final static PrintStream out = null;
//2. System.out 的编译类型是 PrintStream
//3. System.out 的运行类型是 PrintStream
//4. 表示标准输出 显示器
System.out.println(System.out.getClass());
//输出 class java.io.PrintStream
System.out.println("sys学java");
Scanner scanner = new Scanner(System.in);
System.out.println("请输入内容");
String next = scanner.next();
System.out.println(next);
}
}
当我们使用字符流来读取一个文件的时候,默认是按照 utf-8 来读取的;
但是当一个文件的格式不是utf-8的时候,就会出现乱码的情况
public class CodeQuestion {
public static void main(String[] args) throws IOException {
//1. 创建字符输入流 BufferedReader[处理流]
//2. 使用 BufferedReader 对象读取 a.txt
//3. 默认情况下,读取的文件是按照 utf-8 编码
String filePath = "E:\\study.txt";
BufferedReader bur = new BufferedReader(new FileReader(filePath));
String s = bur.readLine();
System.out.println("读取到的内容:"+s);
bur.close();
}
}
因此就引出了转换流 InputStreamReader 和 OutputStreamWriter
编程将 字节流FilelnputStream 包装成(转换成)字符流InputStreamReader, 对文件进行读取(按照 utf-8/gbk 格式),进而在包装成 BufferedReader
public class InputStreamReader_ {
//演示使用 InputStreamReader 转换流解决中文乱码问题
//将字节流 FileInputStream 转成字符流 InputStreamReader,指定编码 gbk/utf-8
public static void main(String[] args) throws IOException {
String filePath = "E:\\study.txt";
//1. 把 new FileInputStream 转成 InputStreamReader
//2. 指定编码 gbk
//InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath),"gbk");
//3. 把 InputStreamReader 传入 BufferedReader
//BufferedReader bfr = new BufferedReader(isr);
//一般将2和3合到一起
BufferedReader bfr = new BufferedReader(new InputStreamReader(
new FileInputStream(filePath),"gbk"));
String s = bfr.readLine();
System.out.println("读取内容 = "+s);
bfr.close();
}
}
编程将 字节流 FileOutputStream 包装成(转换成)字符流OutputStreamWriter
对文件进行写入(按照gbk格式,可以指定其他,比如utf-8)
public class OutputStreamWriter_ {
//演示 OutputStreamWriter 的使用
//把 FileOutputStream 字节流转换成 字符流 OutputStreamWriter
//指定处理的编码 gbk/utf-8
public static void main(String[] args) throws IOException {
String filePath = "E:\\sys.txt";
String charSet = "utf-8";
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), charSet);
osw.write("sys学java,加油!");
osw.close();
System.out.println("按照"+charSet+"保存文件成功");
}
}
PrintStream简单应用
public class OutputStreamWriter_ {
//演示 OutputStreamWriter 的使用
//把 FileOutputStream 字节流转换成 字符流 OutputStreamWriter
//指定处理的编码 gbk/utf-8
public static void main(String[] args) throws IOException {
String filePath = "E:\\sys.txt";
String charSet = "utf-8";
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), charSet);
osw.write("sys学java,加油!");
osw.close();
System.out.println("按照"+charSet+"保存文件成功");
}
}
PrintWriter简单应用
public class PrintWriter_ {
//演示 PrintWriter 使用方式(字符流)
public static void main(String[] args) throws IOException {
//PrintWriter printWriter = new PrintWriter(System.out);//打印到显示器
PrintWriter printWriter = new PrintWriter(new FileWriter("E:\\456.txt"));
printWriter.print("欢迎来到江苏");
printWriter.close();//flush + 关闭流, 才会将数据写入到文件..
}
}
看以下需求:
请问编程读取 ip 、user 和 pwd 的值是多少?
分析
首先我们用传统的方法来处理:
public class Properties01 {
public static void main(String[] args) throws IOException {
//读取 mysql.properties 文件,得到 ip , user 和 pwd
BufferedReader bur = new BufferedReader(new FileReader("src\\mysql.properties"));
String line = "";
while ((line = bur.readLine()) != null) {
//System.out.println(line);
String[] split = line.split("=");
//如果我们要求指定的ip值
if ("ip".equals(split[0])) {
System.out.println(split[0] + "的值是" + split[1]);
}
}
}
}
由上代码可见,要是我们想要获取相对应的信息,需要我们自己去操作相应的代码,比较麻烦,由此就引出了使用Properties类处理。
使用Properties类完成对 mysql.properties 的读取,
public class properties02 {
public static void main(String[] args) throws IOException {
//使用 properties 类来读取 mysql.properties 文件
//1. 创建 Properties 对象
Properties properties = new Properties();
//2. 加载指定的配置文件
properties.load(new FileReader("src\\mysql.properties"));
//3. 把 k-v 显示控制台
properties.list(System.out);
//4. 根据 key 获取 value
String user = properties.getProperty("user");
String pwd = properties.getProperty("pwd");
System.out.println("用户名 =" + user);
System.out.println("密码 =" + pwd);
}
}
使用Properties类添加key-val 到新文件 mysql2.properties 中
public class Properties03 {
public static void main(String[] args) throws IOException {
//使用Properties类添加key-val 到新文件 mysql2.properties 中
//创建对象
Properties properties = new Properties();
//创建内容
properties.setProperty("charset", "utf-8");
properties.setProperty("user", "杰克");//注意保存时,是中文的 Unicode 码值
properties.setProperty("psd", "666");
//将 k-v 储存文件中即可
//null的位置是注释 comments
//一般情况下,没有特殊要求就写为null
properties.store(new FileOutputStream("src\\mysql2.properties"), null);
System.out.println("保存配置文件成功~");
}
}
使用Properties类完成对 mysql2.properties 的读取,并修改某个key-val
public class Properties04 {
public static void main(String[] args) throws IOException {
//使用Properties类添加key-val 到新文件 mysql2.properties 中
//创建对象
Properties properties = new Properties();
//创建内容
//1. 如果该文件没有 key,就是创建
//2. 如果该文件有 key,就是修改
/*
Properties 的父类是 HashTable ,底层就是HashTable的核心方法
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry entry = (Entry)tab[index];
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
addEntry(hash, key, value, index);
return null;
}
*/
properties.setProperty("charset", "utf-8");
properties.setProperty("user", "汤姆");//注意保存时,是中文的 Unicode 码值
properties.setProperty("psd", "888");
//将 k-v 储存文件中即可
//null的位置是注释 comments
//一般情况下,没有特殊要求就写为null
properties.store(new FileOutputStream("src\\mysql2.properties"), null);
System.out.println("保存配置文件成功~");
}
}
public class Homework01 {
/*
1. 在判断e盘下是否有文件夹mytemp ,如果没有就创建mytemp
2. 在e:\mytemp 目录下, 创建文件 hello.txt
3. 如果hello.txt 已经存在,提示该文件已经存在,就不要再重复创建了
4. 并且在hello.txt 文件中,写入 hello,world~
*/
public static void main(String[] args) throws IOException {
//1. 在判断e盘下是否有文件夹mytemp ,如果没有就创建mytemp
String directoryPath = "E:\\mytemp";
File file = new File(directoryPath);
//判断是否存在
if (!file.exists()) {
if (file.mkdirs()) {
System.out.println("创建" + directoryPath + "成功");
} else {
System.out.println("创建" + directoryPath + "失败");
}
}
/*2. 在e:\mytemp 目录下, 创建文件 hello.txt
也可以这样写
String fileName = "hello.txt";
File file2 = new File(directoryPath, fileName);
*/
//2. 在e:\mytemp 目录下, 创建文件 hello.txt
String filePath = directoryPath + "\\hello.txt";
file = new File(filePath);
//判断是否存在
if (!file.exists()) {
if (file.createNewFile()) {
System.out.println("创建" + file + "成功");
//4. 并且在hello.txt 文件中,写入 hello,world~
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file));
bufferedWriter.write("hello,world~");
//关闭流
bufferedWriter.close();
} else {
System.out.println("创建" + file + "失败");
}
} else {
//3. 如果hello.txt 已经存在,提示该文件已经存在,就不要再重复创建了
System.out.println(file + "已经存在,不用重复创建");
}
/*4. 并且在hello.txt 文件中,写入 hello,world~
也可以这样写
FileOutputStream fos = new FileOutputStream(file2);
String buf = "hello,world~";
fos.write(buf.getBytes(), 0, buf.length());
*/
}
}
要求: 使用BufferedReader读取一个文本文件,为每行加上行号再连同内容一并输出到屏幕上。
public class Homework02 {
public static void main(String[] args) throws IOException {
String filePath = "E:\\note.txt";
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
String line = "";
int i = 1;
while ((line = bufferedReader.readLine()) != null) {
System.out.println("第" + (i++) + "行 =" + line);
}
//关闭流
bufferedReader.close();
}
}
如果把文件的编码 改成了 gbk,出现中文乱码,大家思考如何解决
1.创建一个转换流 InputStreamReader 对象,将文件转换为 gbk 格式
2.把 InputStringReader 传入 BufferedReade,然后读取文件.
public class Homework02a {
public static void main(String[] args) throws IOException {
String filePath = "E:\\note.txt";
//1. 创建一个转换流 InputStreamReader 对象
//转换为 gbk 格式
InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath),"gbk");
//2. 把 InputStringReader 传入 BufferedReader
BufferedReader bufferedReader = new BufferedReader(isr);
String line = "";
int i = 1;
while ((line = bufferedReader.readLine()) != null) {
System.out.println("第" + (i++) + "行 =" + line);
}
//关闭流
bufferedReader.close();
}
}
public class Homework03 {
/*
1. 要编写一个dog.properties
name=tom
age=5
color=red
2. 编写Dog 类(name,age,color) 创建一个dog对象,读取dog.properties 用相应的内容完成属性初始化,并输出
3. 将创建的Dog 对象 ,序列化到 文件 dog.dat 文件
4. 将序列化的文件反序列化恢复数据
*/
public static void main(String[] args) throws IOException, ClassNotFoundException {
//1. 要编写一个dog.properties
// name=tom
// age=5
// color=red
Properties properties = new Properties();
properties.setProperty("charset", "utf-8");
properties.setProperty("name", "tom");
properties.setProperty("age", "5");
properties.setProperty("color", "red");
properties.store(new FileOutputStream("src\\dog.properties"), null);
System.out.println("文件创建成功");
// 加载指定的配置文件
properties.load(new FileReader("src\\dog.properties"));
String name = properties.get("name") + "";//Object -> String
int age = Integer.parseInt(properties.get("age") + "");//Object -> int
String color = properties.get("color") + "";//Object -> String
//创建一个Dog对象,完成属性初始化
Dog dog = new Dog(name, age, color);
System.out.println(dog);
//3. 将创建的Dog 对象 ,序列化到 文件 dog.dat 文件
//进行序列化
String filePath = "E:\\dog.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
oos.writeObject(dog);
//关闭流
oos.close();
System.out.println("====序列化完成====");
//4. 将序列化的文件反序列化恢复数据
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
Object dog2 = ois.readObject();
System.out.println("====反序列化后====");
System.out.println("dog的信息 =" + dog2);
//关闭流
ois.close();
}
}
//2. 编写Dog 类(name,age,color) 创建一个dog对象,
// 读取dog.properties 用相应的内容完成属性初始化,并输出
class Dog implements Serializable {
private String name;
private int age;
private String color;
public Dog(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
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 getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}';
}
}