首先来看一个字节流和字符流与处理流的应用:
package javaIO.com;
import java.io.IOException;
import java.io.*;
//文件字节流转字符流复制
public class TestIO {
public static void main(String[] args) {
BufferedInputStream in=null;
PrintStream out=null;
try{
in = new BufferedInputStream(new FileInputStream( "D:\\student_file.txt"));
out = new PrintStream( new
BufferedOutputStream( new FileOutputStream("D:\\student_score.txt")));
System.setIn(in); System.setOut(out); System.setErr(out);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s;
while((s = br.readLine()) != null) System.out.println(s);
System.out.println("复制成功!!!!");
}
catch(IOException iox){
System.out.println("复制失败!!!!!");
}finally {
try {
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
那为什麽需要将字节流转换成字符流呢?因为我们一般的文档都是UTF-8格式编码的;不管用字节流还是字符流进行复制都是可以的,不会出现乱码,但如果是其他格式的编码呢?比如gbk或者是其他的编码,在读取过程中就可能出现乱码;当然处理流呢只是多了一个缓冲区,更能够实现更多类的对象的处理,比如说字符串,数组等其流的统一处理
那为了解决不同编码文件所带来的问题;我们来看看下面这个例子:
首先看从指定编码的文件内容读出的例子:
package javaIO.com;
import java.io.*;
@SuppressWarnings({"all"})
public class InputStreamReader_ {
public static void main(String[] args) throws IOException {
Test1();
}
//演示使用 InputStreamReader 将字节流转换为字符流
//将字节流 FileInputStream 转成字符流 InputStreamReader,指定编码 gbk/utf-8/utf8
public static void Test1() throws IOException{
String sc="D:\\student_file.txt";
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(sc),"utf-8"));
String s;
System.out.println("读取内容:");
while((s= br.readLine())!=null){
System.out.println(s);
}
br.close();//关闭外层流
}
}
接下来我们看对一些内容进行复制并改变编码的例子:
package javaIO.com;
import java.io.*;
@SuppressWarnings({"all"})
public class InputStreamReader_ {
public static void main(String[] args) throws IOException {
Test2();
}
//演示使用 OutputStreamWriter 将字节流转换为字符流
//将字节流 FileOutputStream 转成字符流 OutputStreamWriter,指定编码 gbk/utf-8/utf8
public static void Test2() throws IOException{
String sc="D:\\majunyi.txt";//输出文件
BufferedWriter bs=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(sc),"utf-8"));
bs.write("风煞 JAVA");
bs.newLine();//换行
String scr="D:\\student_file.txt";//输入文件
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(scr),"gbk"));
String s;
while((s= br.readLine())!=null){
bs.write(s);
bs.newLine();
}
bs.close();
br.close();//必须关闭,否则副本中无内容
System.out.println("复制成功!!!");
}
}
注意:在进行文件复制时结束后必须要关流(bs.close();)或者刷新(bs.flush();),否则看不到任何内容,因为只有在关流或者刷新后文件才会开始在硬盘中开始复制。
下面我们来看一下用字符流与处理流相结合实现文本本文档的复制:
package javaIO.com;
import java.io.IOException;
import java.io.*;
//文件字符流复制
@SuppressWarnings({"all"})//镇压警告
public class TestIO {
public static void main(String[] args) {
String line;
BufferedWriter dest=null;
BufferedReader source=null;
try{
dest=new BufferedWriter(new FileWriter("D:\\student_file.txt",true));//以追加的方式复制
source=new BufferedReader(new FileReader("D:\\studentscore.txt"));
line=source.readLine();//按行读取
while(line!=null){
dest.write(line);
dest.newLine();//换行
line=source.readLine();
}
System.out.println("复制成功........");
}catch (IOException e){
e.fillInStackTrace();
}finally {
try{
dest.close();
source.close();
}catch (IOException e){
e.fillInStackTrace();
}
}
}
}
注意:在这里我们直接用字节流对文本文件进行复制也是没有问题的,我就不演示了
另外我们来看一下图片或者视频的复制;当然这里就应该用字节流处理了:
package javaIO.com;
import java.io.IOException;
import java.io.*;
public class TestIO {
public static void main(String[] args) {
JpgTest();
}
//图片复制
public static void JpgTest(){
String srcFilePath="D:\\majunyi.jpg";
String dastFilePath="D:\\zhangyi.jpg";
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
bis=new BufferedInputStream(new FileInputStream(srcFilePath));
bos=new BufferedOutputStream(new FileOutputStream(dastFilePath));
byte[] buff=new byte[1024];
int readLen=0;
while((readLen= bis.read(buff))!=-1){
bos.write(buff,0,readLen);
}
System.out.println("文件拷贝完毕!!!");
} catch (IOException e) {
e.printStackTrace();
}finally {//关闭文件!
try {
if(bis!=null){
bis.close();
}
if (bos!=null){
bos.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
}
注意:这里
byte[] buff=new byte[1024];
int readLen=0;
while((readLen= bis.read(buff))!=-1){
bos.write(buff,0,readLen);
}
不管对图片复制还是对视频复制;如果用字节数组时必须用readLen记录bis.read(buff)读到的字节数,用 bos.write(buff,0,readLen);写入指定长度的字符数组;否则将出错,因为在结束时不一定读到整个字节数组的字节,图片和视频的复制要求是比较严格的,大家要注意。
最后我为大家介绍对象流实现数据的序列化;
那什么是数据的序列化呢?比如我们平时要保存一个 int类型的100;我们可以直接写入100;但他是以一个int类型的100保存还是一个字符串或者是其他的东西呢?
所以简单来说数据的序列化就是不仅要存数据还要保存数据的类型;但是如果要实现对象的序列化,那么这个类一定要实现Serializable接口,(还可以实现另外一个接口,但由于Serializable是一个空接口里面没有方法,不需要进行覆写,所以一般实现Serializable接口更方便)而且基本数据类型都是直接或间接实现Serializable接口的,所以可以对任意基本数据类型的对象序列化,其他对象的序列化必须实现Serializable接口。
我们先来看对一些基本数据和某各类的对象进行序列化的例子:
package javaIO.com;
import java.io.IOException;
import java.io.*;
@SuppressWarnings({"all"})
class Dog implements Serializable{//如果要序列化某个对象,必须实现 Serializable 接口
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
@SuppressWarnings({"all"})//镇压警告
public class TestIO {
public static void main(String[] args) throws Exception{
ObjectOutputStreamTest();
}
//演示ObjectOutputStream的数据序列化
public static void ObjectOutputStreamTest() throws Exception{
//序列化后,文件保存格式不是文本,而是按照他自己的格式来保存
String filepath="D:\\date.dat";
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(filepath));
//Java 的序列化不能对 static 和 transient(短暂的)修饰的属性进行保存
// 也就是说Java 不能序列化tatic 和 transient(短暂的)修饰的属性
//序列化数据到D:\\date.dat
oos.writeInt(129);//int -> Integer (实现了 Serializable)
oos.writeBoolean(true);//boolean -> Boolean (实现了 Serializable)
oos.writeChar('K');//char ->Character (实现了 Serializable)
oos.writeUTF("风煞.JAVA");//String
//保存一个Dog 对象 构造Dog类
oos.writeObject(new Dog("旺财",4));
oos.close();//关流
System.out.println("数据保存完毕!!!");
}
}
接下来我们试着将刚才序列化的数据反序列化读出:
package javaIO.com;
import java.io.IOException;
import java.io.*;
@SuppressWarnings({"all"})
class Dog implements Serializable{//如果要序列化某个对象,必须实现 Serializable 接口
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
@SuppressWarnings({"all"})//镇压警告
public class TestIO {
public static void main(String[] args) throws Exception{
}
//演示ObjectInputStream的数据反序列化
public static void ObjectInputStreamTest() throws Exception{
//数据反序列化文件
String filepath="D:\\date.dat";
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filepath));
//反序列化数据读取顺序必须与序列化保存时顺序相同!!!! 否则会出现异常
System.out.println(objectInputStream.readInt());
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readChar());
System.out.println(objectInputStream.readUTF());
// System.out.println(objectInputStream.readObject()); 将会抛出异常!!!
Object dog =objectInputStream.readObject();
System.out.println("Object o 运行类型"+dog.getClass());
System.out.println("dog 信息:"+dog);
objectInputStream.close();//记得关流
System.out.println("数据读出成功!!!");
//试着调用dog的get方法
//由于此时的dog时Object类的,调用get方法需要进行向下转型
Dog dog1=(Dog) dog;
System.out.println("名字:"+dog1.getName());
System.out.println("年龄:"+dog1.getAge());
}
}
注意:反序列化数据读取顺序必须与序列化保存时顺序相同!!!! 否则会出现异常
下面来看看打印流吧:
package javaIO.com;
import org.junit.jupiter.api.Test;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
// java io流 打印流 PrintStream(字节流) 和PrintWriter(字符流)
public class PriintFile_ {
public static void main(String[] args) {
}
@Test
public void PrintWriter_() throws IOException{
PrintWriter printWriter=new PrintWriter(new FileWriter("D:\\PrintStream_.txt"));
printWriter.println("manuidshybgfheswd");
printWriter.close();
}
@Test
public void PrintStream_() throws IOException{
PrintStream out= System.out;
// 在默认情况下, PrintStream 输出数据的位置是 标准输出,即显示器
out.print("jhon,hello");
// 因为print的底层是调用write 实现的,因此也可以这样操作
out.write("majunyi".getBytes(StandardCharsets.UTF_8));
// 打印流 PrintStream(字节流) 可以更改输出位置
System.setOut(new PrintStream("D:\\PrintStream_.txt"));
System.out.println("majnuyi");
out.print("majunyi_txt");
out.close();
}
}
看到这里是不是觉得眼熟呢,在文章开头就有介绍啦,它可以用来确定流的打印位置。
另外在上面一段代码中我使用了java 的JUnit 测试框架( @Test ),如果有不懂的朋友呢,我在我的另一篇文章(java 泛型 及 java JUnit 测试框架) 中配有截图和详细讲解,大家可以去进行参考。
那么现在就是我们的 Properties 类对文件的操作啦:
首先来看一下如果没有Properties 类我们如何对文件进行操作:
先看看我们mysql.properties 文件中的内容:
接下来我们需要将指定的内容读出:
public class propertiesFile {
public static void main(String[] args) throws IOException{
Test01();
}
// 普通方法读取文件想要的内容:
public static void Test01() throws IOException {
// 读取mysql.properties 文件,并得到ip,User,和 pwd
BufferedReader reader = new BufferedReader(new FileReader("src\\mysql.properties"));
String s=null;
while ((s=reader.readLine())!=null){
// s只要后面部分需要对字符串进行拆分
String[] split = s.split("=");
System.out.println(split[0]+"是"+split[1]);
}
}
}
运行示例:
那这样如果需要创建文件和实现对文件进行更改都是比较麻烦的,那让我们来看看 Properties 类所能实现的功能吧:
package javaIO.com;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
// 演示 properties 类对文件的操作
public class propertiesFile {
public static void main(String[] args) throws IOException{
Test02();
Test03();
}
/**
* properties 使用示例
* 常用方法:
* 1. load:加载配置文件的键值对到 Properties 对象
* 2. list: 将数据显示到指定设备 流对象
* 3. getProperty(key): 根据键获取值
* 4.setProperty(key,value): 设置键值对到Properties 对象
* 5. store: 将Properties中的键值对储存到配置文件,在IDEA 中,保存信息到配置文件,如果含有中文,会存储为Unicode码
*/
public static void Test02() throws IOException{
// 1. 创建 Properties 对象
Properties properties = new Properties();
// 2. 加载 src\mysql.properties 文件
properties.load(new FileReader("src\\mysql.properties"));
// 3. 把 K-V 显示出来
properties.list(System.out);
// 4. 根据 Key 获取
System.out.println(properties.getProperty("User")+"\n"+
properties.getProperty("ip")+"\n"+properties.getProperty("pwd")+"\n\n\n\n");
}
/**
* 1. 使用Properties 类对mysql.properties 的读取
* 2. 使用Properties 类添加Key-Value 到新文件 mysql2.properties 中
* 3. 使用Properties 类完成对mysql.properties 的读取,并修改某个值
* 注意: Properties 的底层为Hashtable, 则其底层核心代码为 Hashtable
*/
public static void Test03() throws IOException{
// 使用Properties 类来对文件内容进行配置
Properties properties = new Properties();
// 创建
properties.setProperty("charset","UTF-8");
properties.setProperty("User","汤姆");// 中文保存为 Unicode 码
properties.setProperty("pwd","abc1234");
// 将K-V 存储到文件中即可
properties.store(new FileOutputStream("src\\mysql2.properties"),"majnuyi");
// 第二个参数代表文件的注释 null 代表没有注释
// 修改 setProperty,如果存在Key,则为修改,若key 存在,则为创建
properties.setProperty("User","tom-jact");
properties.store(new FileOutputStream("src\\mysql2.properties"),"majnuyi");
}
}
来看看运行效果吧:
现在 mysql2.properties 文件中的内容:
我的演示及讲解就到这里啦,还有很对方法希望大家下来自己研究呢,我展示的只是平时较为常用的方法,谢谢大家,有问题评论区留言哦!!!