Java基础——IO流
1、IO流
IO流:输入、输出流(针对的是内存和外围设备(硬盘)的数据交换)
外围设备到内存:输入(读)
内存到外围设备:输出(写)
字符流的由来:其实就是字节流读取文字字节数据后,不直接操作而是先指定的编码表,获取对应的文字
再对这个文字进行操作。简单的说:字节流+编码表。
字节流的两个顶层父类:
1、InputStream
2、OutputStream
字符流的两个顶层父类:
1、Reader
2、Writer
如果要操作文字数据,优先考虑字符流,将数据从内存写到硬盘上,要使用字符流中的输出流:Writer
字符流缓冲区:
BufferWriter
newLine():加入换行符
BufferReader
readLine():读取文本的一行
2、字符流的操作代码示例
2.1字符流读写操作
读操作
package cn.itcast.p2.io.filewriter;
//读文件的第一种方式
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
// 1、创建读取字符数据的流对象
/*
* 在创建读取流对象时,必须要明确被读取的文件,一定要确定该文件是存在的
* 用一个读取流关联一个已存在文件
*
*
* */
FileReader fr=new FileReader("demo.txt");
int ch;
// 用Reader中的read方法读取字符
// int ch=fr.read();//每次只读取一个字符,而且是二进制(因为存在磁盘上的都是二进制格式的,由于前面int限制,所以返回的十进制数)
// System.out.println(ch);//结果:97,读完之后返回的是-1
while((ch=fr.read())!=-1) {
System.out.println((char)ch);
}
}
}
package cn.itcast.p2.io.filewriter;
//读文件的第二种方式
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo2 {
public static void main(String[] args) throws IOException {
FileReader fr=new FileReader("demo.txt");
/*使用read(char[])读取文本文件数据
* 先创建字符数组
*
* */
/*char[]buf=new char[6];
int num=fr.read(buf);//返回读取到字符数,并把字符存储到buf数组中
System.out.println(num+":"+new String(buf));//结果:6:abcd(后面有两空格)
int num1=fr.read(buf);
System.out.println(num1+":"+new String(buf));//结果:6:adfalx(会把之前的覆盖掉)
int num2=fr.read(buf);
System.out.println(num1+":"+new String(buf));//6:ixixlx
int num3=fr.read(buf);
System.out.println(num3+":"+new String(buf));//-1:ixixlx(当读到-1直接返回)
*/
char[]buf=new char[1024];//一般设置1024的整数倍,以免反复执行下面的语句,提高效率
int len;
while((len=fr.read(buf))!=-1) {
System.out.println(new String(buf,0,len));
}
}
}
写操作
package cn.itcast.p2.io.filewriter;
//写文字到硬盘
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//创建一个可以往文件中写入字符数据的字符输出流对象
/*
* 既然是往一个文件中写入文字数据,那么在创建对象时,就必须明确该文件(用于存储数据的目的地)
* 如果文件不存在,则会自动创建
* 如果文件存在,则会被覆盖
*
* */
// FileWriter fw=new FileWriter("demo.txt");
// 如果构造函数中加入true,可以实现对文件进行续写
FileWriter fw=new FileWriter("demo.txt",true);
/*
* 调用Writer对象中的write(string)方法,写入数据
* 其实数据写入到临时存储缓冲区中
* */
// fw.write("abcde");
fw.write("abcd"+LINE_SEPARATOR+"adfal");//加入换行符
fw.write("xixix");//续写入文件
/*
* 进行刷新,将数据直接写到目的地中
* */
fw.flush();
/*
* 关闭流,关闭资源,在关闭流的时候会先调用flush刷新缓冲区中的数据到目的地
* */
fw.close();
}
}
2.1.1 读写实例代码
package cn.itcast.p2.io.filewriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyTextTest {
/*
* 将C盘中的一个文件复制到D盘
* 思路:
* 1、需要读取源
* 2、将读到的原数据写入到目的地
* 3、既然是操作文本数据,使用字符流
* */
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//1、读取一个已有的文本文件,使用字符读取流和文件相关联
FileReader fr=new FileReader("笔记.txt");
//2、创建一个目的地,用于存储读到数据
FileWriter fw=new FileWriter("copytext_1.txt");
//3、频繁的读写操作
int ch=0;
while((ch=fr.read())!=-1)
{
System.out.println(ch);
fw.write(ch);
}
//4、关闭流资源
fw.close();
fr.close();
}
}
读写异常捕捉
package cn.itcast.p2.io.filewriter;
//异常处理
import java.io.FileWriter;
import java.io.IOException;
public class IOExceptionDemo {
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static void main(String[] args) {
// TODO Auto-generated method stub
FileWriter fw=null;//在外面声明
try {
fw = new FileWriter("demo.txt");//在里面初始化 位置1
fw.write("abcd" + LINE_SEPARATOR + "adfal");//加入换行符 位置2
} catch (IOException e) {
// TODO: handle exception
System.out.println(e.toString());
}finally {
if(fw!=null)//需要判断它是否为空才能进行下面的fw.close()操作,因为位置1抛出异常时(路径不存在),fw就不存在,为此它也会抛异常
//当有限制时,就可以很明确的捕捉到是否是位置2发生写入异常
try {
fw.close();//如果不再外面声明,此处就会报错,fw变量没被定义
} catch (IOException e) {
// TODO Auto-generated catch block
throw new RuntimeException("关闭失败");
}//
}
}
}
package cn.itcast.p2.io.filewriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyTextTest_2 {
private static final int BUFFER_SIZE = 1024;
public static void main(String[] args) {
// TODO Auto-generated method stub
FileReader fr=null;
FileWriter fw=null;
try {
fr=new FileReader("笔记.txt");
fw=new FileWriter("copytest_2.txt");
//创建一个临时容器,用于缓存读取到的字符
char[] buf=new char[BUFFER_SIZE];
//定义一个变量记录读取到的字符数(其实就是往数组里装的字符个数)
int len=0;
while((len=fr.read(buf))!=-1) {
fw.write(buf, 0, len);
}
}
catch(Exception e) {
throw new RuntimeException("读写失败");
}finally {
if(fw!=null)
try {
fw.close();
}catch(IOException e) {
}
if(fr!=null)
try {
fr.close();
}catch(IOException e){
}
}
}
}
获取文本的行号
package cn.itcast.p2.io.wrapper;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
public class LineNumberReaderDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileReader fr=new FileReader("笔记.txt");
LineNumberReader lnr=new LineNumberReader(fr);
String line=null;
// lnr.setLineNumber(100);//设置文本开始行
while((line=lnr.readLine())!=null)
{
System.out.println(lnr.getLineNumber()+":"+line);//获取文本的行号
}
lnr.close();
}
}
2.2字符流缓冲区读写操作
package cn.itcast.p2.io.charstream.test;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyTextByBufTest {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileReader fr=new FileReader("buf.txt");
BufferedReader bufr=new BufferedReader(fr);
FileWriter fw=new FileWriter("buf_copy2.txt");
BufferedWriter bufw=new BufferedWriter(fw);
String line=null;
//按行读写
while((line=bufr.readLine())!=null) {
bufw.write(line);
bufw.newLine();
bufw.flush();
}
/*int ch=0;
while((ch=bufr.read())!=-1) {
bufw.write(ch);
}*/
bufw.close();
bufr.close();
}
}
package cn.itcast.p2.io.charstream.test;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferWriterDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileWriter fw=new FileWriter("buf.txt");
//为了提高写入的效率,使用了字符流的缓冲区
//创建了一个字符写入流的缓冲区对象,并和指定要被缓冲的流对象相关联
BufferedWriter bufw=new BufferedWriter(fw);
//使用缓冲区的写入方法将数据先写入到缓冲区中
bufw.write("abcd");
bufw.newLine();//写入换行符(只是缓冲区对象有),封装的是System.getProperty("line.separator")
bufw.write("afhsdnajkl");
//使用缓冲区的刷新方法将数据刷到目的地中
bufw.flush();
//关闭缓冲区的(其实关闭的就是被缓冲的流对象)
bufw.close();
}
}
package cn.itcast.p2.io.charstream.test;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
demo();
FileReader fr=new FileReader("buf.txt");
BufferedReader bufr=new BufferedReader(fr);
String line=null;
while((line=bufr.readLine())!=null) {
System.out.println(line);//读取文本的一行
}
bufr.close();
}
private static void demo() throws IOException {
// TODO Auto-generated method stub
FileReader fr=new FileReader("buf.txt");
char[]buf=new char[1024];
int len=0;
while((len=fr.read(buf))!=-1) {
System.out.println(new String(buf,0,len));
}
fr.close();
}
}
2.2.1自定义缓冲区
自定义类
package cn.itcast.p2.io.charstream.mybuffer;
import java.io.FileReader;
import java.io.IOException;
/*
* 自定义的读取缓冲区,其实就是模拟一个BufferedReader
* 分析:
* 缓冲区中无非就是封装了数组
* 并对外提供了更多的方法对数组进行访问
* 其实这些方法最终操作的都是数组的角标
*
* 缓冲的原理:
* 其实就是从源中获取一批数据装进缓冲区中
* 再从缓冲区中不断的取出一个一个数据
*
* 在此次取完后,再从源中继续取一批数据进缓冲区
* 当源中的数据取光时,用-1作为结束标记
* */
public class MyBufferReader {
private FileReader r;
//定义一个数组作为缓冲区
private char[]buf=new char[1024];
//定义一个指针用于操作这个数组中的元素,当操作到最后一个元素后,指针归零
private int pos=0;
//定义一个计数器用于记录缓冲区中的数据个数,当该数据减到0,就从源中继续获取数据到缓冲区中
private int count=0;
MyBufferReader(FileReader r) {
this.r=r;
}
/*
* 该方法从缓冲区中一次取一个字符
*
* */
public int myRead() throws IOException {
if(count==0)
{
count=r.read(buf);
}
if(count<0)
return -1;
char ch=buf[pos++];
count--;
return ch;
/*//1、从源中获取一批数据到缓冲区中,需先做判断,只有计数器为0时,才需要从源中获取数据
if(count==0) {
count=r.read(buf);
if(count<-1)
return -1;
//每次获取数据到缓冲区后,角标归零.
pos=0;
char ch=buf[pos];
pos++;
count--;
return ch;
}else if(count>0) {
char ch=buf[pos];
pos++;
count--;
return ch;
}*/
}
public String myReadLine() throws IOException {
StringBuilder sb=new StringBuilder();
int ch=0;
while((ch=myRead())!=-1) {
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
sb.append((char)ch);
}
if(sb.length()!=0)//没有这个的话,如果最后一行后面没有回车则最后一行打印不出来
return sb.toString();
return null;
}
public void myClose() throws IOException
{
r.close();
}
}
自定义缓冲区应用
package cn.itcast.p2.io.charstream.mybuffer;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class MyBufferedReaderDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
// demo();
FileReader fr=new FileReader("buf.txt");
MyBufferReader bufr=new MyBufferReader(fr);
String line=null;
while((line=bufr.myReadLine())!=null) {
System.out.println(line);//读取文本的一行
}
bufr.myClose();
}
private static void demo() throws IOException {
// TODO Auto-generated method stub
FileReader fr=new FileReader("buf.txt");
char[]buf=new char[1024];
int len=0;
while((len=fr.read(buf))!=-1) {
System.out.println(new String(buf,0,len));
}
fr.close();
}
}
3、字节流读写操作
3.1 字节流读写示例
package cn.itcast.p2.io.bytestream.demo;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
demo_write();
demo_read();
}
private static void demo_read() throws IOException {
// TODO Auto-generated method stub
//创建一个读取流对象和指定文件关联
FileInputStream fis=new FileInputStream("bytesdemo.txt");
byte[]buf=new byte[fis.available()];//文件长度,少用,万一文件16个G,导致内存溢出
fis.read(buf);
System.out.println(new String(buf));
//一次读取一个数组长度,建议使用这种
/*byte[] buf=new byte[1024];
int len=0;
while((len=fis.read(buf))!=-1) {
System.out.println(new String(buf,0,len));
}*/
/*//一次读取一个字节
int ch=0;
while((ch=fis.read())!=-1)
{
System.out.println((char)ch);
}*/
fis.close();
}
private static void demo_write() throws IOException {
// TODO Auto-generated method stub
// 1、创建字节输出流对象,用于操作文件
FileOutputStream fos=new FileOutputStream("bytesdemo.txt");
// 2、写数据,直接写入到了目的地中
fos.write("abcddasf".getBytes());
fos.close();//关闭资源动作
}
}
3.2 字节流缓冲区读写示例
package cn.itcast.p2.io.bytestream.demo;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyMp3Test {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
copy_1();
copy_2();
}
//使用缓冲区复制音频文件
private static void copy_2() throws IOException {
// TODO Auto-generated method stub
FileInputStream fis=new FileInputStream("0.mp3");
BufferedInputStream bufis=new BufferedInputStream(fis);
FileOutputStream fos=new FileOutputStream("2.mp3");
BufferedOutputStream bufos=new BufferedOutputStream(fos);
int ch=0;
while((ch=bufis.read())!=-1) {
fos.write(ch);
}
bufis.close();
bufos.close();
}
private static void copy_1() throws IOException {
// TODO Auto-generated method stub
FileInputStream fis=new FileInputStream("0.mp3");
FileOutputStream fos=new FileOutputStream("1.mp3");
byte[]buf=new byte[1024];
int len=0;
while((len=fis.read(buf))!=-1) {
fos.write(buf,0,len);
}
fos.close();
fis.close();
}
}
4 装饰设计模式
装饰设计模式:
对一组对象的功能进行增强时,就可以使用该模式进行问题的增强
装饰和继承都能事项一样的特点:进行功能的拓展。有什么区别呢?
首先有一个继承体系。
writer
|—TextWriter:用于操作文本
|—MediaWriter:用于操作媒体
想要对操作的动作进行效率的提高。
按照面向对象,可以通过继承对具体的进行功能的扩展
效率提高需要加入缓冲技术
Writer
|—TextWriter:用于操作文本
|—BufferTextWriter:加入了缓冲技术的操作文本对象
|—MediaWriter:用于操作媒体
|—BufferMediaWriter:
如果这个体系进行功能扩展,有多个流对象
那么这个流要提高效率,是不是也要产生子类呢?这时就会发现只为提高功能进行的扩展
导致继承体系越来越臃肿,不够灵活
既然加入的都是同一种技术—缓冲
前一种是让缓冲和具体的对象相结合
可不可以将缓冲进行单独的封装,哪个对象需要缓冲就将那个对象和缓冲关联
class Buffer{
Buffer(TextWriter w)
{}
Buffer(MediaWriter w)
{}
}
装饰类:
class BufferWriter extends Writer{
BufferWriter(Writer w)
{
}
}
Writer
|—TextWriter:用于操作文本
|—MediaWriter:用于操作媒体
|—BufferWriter:用于提高效率
装饰比继承灵活
特点:装饰类和被装饰类都必须所属同一个接口或者父类
举例
package cn.itcast.p2.io.wrapper;
public class PersonDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Person p=new Person();
// p.chifan();
NewPerson p1=new NewPerson(p);
p1.chifan();
NewPerson2 p2=new NewPerson2();
p2.chifan();
}
}
class Person{
void chifan() {
System.out.println("吃饭");
}
}
//这个类的出现是为了增强Person而出现的
class NewPerson{
private Person p;
NewPerson(Person p){
this.p=p;
}
public void chifan() {
System.out.println("开胃酒");
p.chifan();
System.out.println("甜点");
}
}
//继承实现Person的增强
class NewPerson2 extends Person{
public void chifan() {
System.out.println("开胃酒");
super.chifan();
System.out.println("甜点");
}
}
5、转换流操作
5.1 字节流和字符流之间的转换(没有使用转换流)
package cn.itcast.p1.transstream.demo;
import java.io.IOException;
import java.io.InputStream;
/*
* 读取一个键盘录入的数据,并打印在控制台上
* 键盘本身就是一个标准的输入设备
* 对于Java而言,对于这种输入设备都有对应的对象
*
* */
public class TransStreamDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
// readKey();
readKey2();
}
private static void readKey2() throws IOException {
// TODO Auto-generated method stub
/*
* 获取用户键盘录入的数据
* 并将数据变成大写显示在控制台上
* 如果用户输入的是over,结束键盘录入
*
* 思路:
* 1、因为键盘录入只读取一个字节,要判断是否是over,需要将读取到的字节拼成字符串
* 2、那就需要一个容器,StringBuilder
* 3、在用户回车之前将录入的数据变成字符串判断即可
*
* */
// 1、创建容器
StringBuilder sb=new StringBuilder();
// 2、获取键盘读取流
InputStream in=System.in;
// 3、定义变量记录读取到的字节,并循环获取
int ch=0;
while((ch=in.read())!=-1) {
// 在存储之前需要判断是否是换行标记,因为换行标记不存储
if(ch=='\r')
continue;
if(ch=='\n') {
String temp=sb.toString();
if("over".equals(temp))
break;
System.out.println(temp.toUpperCase());
sb.delete(0, sb.length());
}
else
// 将读取到的字节存储到StringBuilder中
sb.append((char)ch);
}
System.out.println(sb);
}
private static void readKey() throws IOException {
// TODO Auto-generated method stub
InputStream in=System.in;
int ch=in.read();//阻塞式方法,没有数据就一直等
System.out.println(ch);
// in.close();//默认的输入设备和输出设备都不需要关闭,一旦关闭则整个
// InputStream in=System.in;int ch=in.read();就会报错,这个流就不存在了,它是随着系统的关闭而消失的,系统运行而存在的(除非系统关了重启)
}
}
5.2 转换流
转换流:
InputStreamReader:字节到字符的桥梁。解码
OutputStreamWriter:字符到字节的桥梁。编码
流的操作规律:
之所以要弄清楚这个规律,是因为流对象太多,开发时不知道用哪个对象合适。
想要知道开发时用到哪些对象,只要通过四个明确即可。
1、明确源和目的(汇)
源:InputStream Reader
目的:OutputStream Writer
2、明确数据是否是纯文本数据
源:是纯文本:Reader
否:InputStream
目的:是纯文本:Writer
否:OutputStream
到这里,就可以明确需求中具体要使用哪个体系
3、明确具体的设备
源设备:
硬盘:File
键盘:System.in
内存:数组(缓冲区)
网络:Socket流
目的设备:
硬盘:File
控制台:System.out
内存:数组
网络:Socket流
4、是否需要其他额外功能
1、是否需要高效(缓冲区);
是,就加上buffer;
例如:
需求1:复制一个文本文件
1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2、是否是纯文本
是!
源:Reader
目的:Writer
3、明确具体设备
源:
硬盘:File
目的:
硬盘:File
FileReader fr=new FileReader(“a.txt”)
FileWriter fw=new FileWriter(“b.txt”)
4、需要额外功能吗?
需要,需要高效
BufferedReader bufr=new BufferedReader(new FileReader(“a.txt”));
BufferedWriter bufw=new BufferedWriter(new FileWriter(“b.txt”));
需求2:将键盘输入数据存储到硬盘
1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2、明确是否是纯文本
是!
源:Reader
目的:Writer
3、明确具体设备
源:
键盘 System.in
目的地:
硬盘 File
InputStream in=System.in
FileWriter fw=new FileWriter(“a.txt”);
这样做可以完成,但是麻烦,将读取的字节数据转成字符串,再由字符流操作
4、需要额外功能吗?
需要。转换将字节流转成字符流。因为明确源是Reader,这样操作文本数据更加便捷
所以要将已有的字节流转成字符流,使用字节—》字符。InputStreamReader
InputStreamReader isr=new InputStreamReader(System.in);
FileWriter fw=new FileWriter(“b.txt”);
还需要功能吗?
需要高效!
BufferReader bufr=new BufferReader(new InputStreamReader(System.in));
BufferWriter bufw=new BufferWriter(FileWriter(“b.txt”));
需求3:将一个文本文件数据显示在控制台上
1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2、明确是否是纯文本
是!
源:Reader
目的:Writer
3、明确具体的设备
源:
硬盘 File
目的:
控制台 System.out
FileReader fr=new FileReader("b.txt");
OutputStream out=System.out;
4、是否需要额外功能
需要转换.因为一个汉字是两个字节,输出是一个一个字节的输出转换成字符操作更加便捷
FileReader fr=new FileReader("a.txt");
OutputStreamWriter osw=new OutputStreamWriter(System.out);
需要高效
BufferedReader bfr=new BufferedReader(new FileReader("a.txt"));
BufferedReader bfw=new BufferedWriter(new OutputStreamWriter(System.out));
需求4:读取键盘录入数据,显示在控制台上
1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2、明确是否是纯文本
是!
源:Reader
目的:Writer
3、明确设备
源:
键盘 System.in
目的地:
控制台 System.out
4、是否需要额外功能?
需要转换,因为都是字节流,但是操作的确实文本数据
所以使用字符流操作起来更为便捷
InputStreamReader isr=new InputStreamReader(System.in);
OutputStreamWriter osw=new OutputStreamWriter(System.out);
为了将其高效
BufferReader bufr=new BufferReader(new InputStreamReader(System.in));
BufferWriter bufw=new BufferWriter(new OutputStreamWriter(System.out));
5、将一个中文字符串数据按照指定的编码表写入到一个文本文件中
1、目的 OutputStream writer
2、是纯文本 Writer
3、设备:硬盘 File
FileWriter fw=new FileWriter("a.txt")
fw.write("你好");
注意:既然需求已经明确了指定编码表的动作
那就不可以使用FileWriter,因为FileWriter内部是使用默认的本地编码表
只能使用其父类 OutputStreamWriter
OutputStreamWriter接收一个字节输出流对象,既然是操作文本文件,那么该对象应该是FileOutputStream
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("a.txt"),编码名字);
需要高效吗?
BufferWriter bufw=new BufferWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),编码名字));
什么时候使用转换流呢?
1、源或者目的对应的设备是字节流,但是操作的却是文本数据,可以使用转换作为桥梁
提高对文本操作的便捷
2、一旦操作文本涉及到具体的指定编码表时,必须使用转换流
5.2.1 字节流转成字符流
package cn.itcast.p1.transstream.demo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class TransStreamDemo_2 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
// 字节流
InputStream in=System.in;
// 将字节转成字符的桥梁,转换流
InputStreamReader isr=new InputStreamReader(in);
// 字符流
BufferedReader bufr=new BufferedReader(isr);
String line=null;
while((line=bufr.readLine())!=null) {
if("over".equals(line))
break;
System.out.println(line.toUpperCase());
}
}
}
缓冲区+转换流
package cn.itcast.p1.transstream.demo;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class TransStreamDemo_3 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
String line=null;
while((line=bufr.readLine())!=null) {
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
}
}
编码问题
package cn.itcast.p1.transstream.demo;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
public class TransStreamDemo_5 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
writeText();
writeText_1();
writeText_2();
readText();
readText_1();
}
private static void readText_1() throws IOException {
// TODO Auto-generated method stub
// 用什么编码就用什么解码
InputStreamReader isr=new InputStreamReader(new FileInputStream("gbk_2.txt"),"gbk");
char[] buf=new char[10];
int len=isr.read(buf);
String str=new String(buf,0,len);
System.out.println(str);
isr.close();
}
private static void readText() throws IOException {
// TODO Auto-generated method stub
FileReader fr=new FileReader("gbk_2.txt");//因为编码是gbk,而默认编码是utf-8所以解码的时候乱码
char[] buf=new char[10];
int len=fr.read(buf);
String str=new String(buf,0,len);
System.out.println(str);
fr.close();
}
private static void writeText_2() throws IOException {
// TODO Auto-generated method stub
// 用utf-8进行编码其中的文本
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("u8_1.txt"),"utf-8");
osw.write("你好");
osw.close();
}
private static void writeText_1() throws IOException {
// TODO Auto-generated method stub
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("gbk_2.txt"),"GBK");
/*
* FileWriter fw=new FileWriter("gbk_1.txt");
* 这句代码和上面的功能是一样的
* FileWriter:其实就是转换流指定了本机默认码表的体现。而且这个转换流的子类对象,可以方便操作文本文件
* 简单说:操作文件的字节流+本机默认的编码表(utf-8)
* 如果操作文本文件需要明确具体的编码。FileWriter就行不通了,它不能改变编码,只能使用转换流了
*
* */
osw.write("你好");
osw.close();
}
private static void writeText() throws IOException {
// TODO Auto-generated method stub
FileWriter fw=new FileWriter("gbk_1.txt");
fw.write("你好");
fw.close();
}
}
6、文件操作
6.1 封装成文件对象
package cn.itcast.p2.File.demo;
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
constructorDemo();
}
private static void constructorDemo() {
// TODO Auto-generated method stub
// 可以将一个已存在的或者不存在的文件或者目录封装成File文件对象
File file=new File("a.txt");
// 以下两种方法和上面一样,只不过下面的将路径和文件名分开了,上面的可以使用绝对路径
/*File f2=new File("c:\\","a.txt");
File f=new File("c:\\");
File f3=new File(f,"a.txt");*/
// File.separator表示路径分割符:window下是:\\ Linux下是:\
File f4=new File("c:"+File.separator+"abc"+File.separator+"a.txt");
System.out.println(f4);
}
}
6.2 文件的基本操作
package cn.itcast.p2.File.demo;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
public class FileMethodDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
/*
* File对象的常见方法
* 1、获取
* 1.1获取文件名称
* 1.2获取文件路径
* 1.3获取文件大小
* 1.4获取文件修改时间
* 2、创建与删除
* boolean
* 3、判断
* 4、重命名
*
* */
// getDemo();
// createAndDeleteDemo();
// isDemo();
// renameToDemo();
listRootDemo();
}
private static void listRootDemo() {
// TODO Auto-generated method stub
File file=new File("d:\\");
System.out.println("getFreeSpace:"+file.getFreeSpace());//打印空闲空间
System.out.println("getTotalSpace:"+file.getFreeSpace());//打印总共空间
System.out.println("getUsableSpace:"+file.getFreeSpace());//打印可用空间
// File[]files=File.listRoots();
// for(File file:files)
// System.out.println(file);//打印根目录,即C:\ D:\ E:\ F:\
}
private static void renameToDemo() {
// TODO Auto-generated method stub
File f1=new File("a.txt");
File f2=new File("aa.txt");
boolean b=f1.renameTo(f2);//将a.txt重命名为aa.txt,如果是aa.txt和a.txt是不同的盘,则变成了剪切并重命名,a.txt不存在了,变成了其他盘的aa.txt
System.out.println("b="+b);
}
private static void isDemo() {
// TODO Auto-generated method stub
File f=new File("a.txt");
// boolean b=f.exists();//判断文件是否存在
// System.out.println(b);
System.out.println(f.isDirectory());//判断是否是目录
System.out.println(f.isFile());//判断是否是文件,一般先判断是否存在再判断文件与否,假如不存在,则会返回false
}
private static void createAndDeleteDemo() throws IOException {
// TODO Auto-generated method stub
File file=new File("file.txt");
/*
* 和输出流不一样,如果文件不存在则创建,存在则不创建
* */
// boolean b=file.createNewFile();//创建新文件
// System.out.println("b="+b);
//创建目录
/*File dir=new File("abc");
* File dir1=new File("abc\\d\\d\cc");
boolean b=dir1.mkdirs();//创建多级目录
dir.mkdir();//创建单级目录
System.out.println("b="+b);
System.out.println(dir.delete());//删除目录,里面如果有文件则删不掉,删除多级目录时只删除了最里面的那个目录
*/
boolean b=file.delete();//删除文件
}
private static void getDemo() {
// TODO Auto-generated method stub
File file=new File("a.txt");
String name=file.getName();//获取文件名称
String absPath=file.getAbsolutePath();//获取文件绝对路径
String path=file.getPath();//获取相对路径
long len=file.length();//获取文件大小
long time=file.lastModified();//获取最近一次修改时间
Date date=new Date(time);
DateFormat dateFormat=DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
String str_time=dateFormat.format(date);
System.out.println("parent path:"+file.getParent());//获取文件的父目录
System.out.println(name);
System.out.println(absPath);
System.out.println(path);
System.out.println(len);
System.out.println(time);
System.out.println(str_time);
}
}
6.3 过滤文件
过滤器
隐藏文件的过滤器
package cn.itcast.p2.filter;
import java.io.File;
import java.io.FileFilter;
import java.nio.file.Path;
public class FilterByHadden implements FileFilter {
@Override
public boolean accept(File pathname) {
// TODO Auto-generated method stub
return !pathname.isHidden();
}
}
后缀名的过滤器(.java)
package cn.itcast.p2.filter;
import java.io.File;
import java.io.FilenameFilter;
public class filterByName implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
// TODO Auto-generated method stub
return name.endsWith(".java");
}
}
后缀名的通用过滤器
package cn.itcast.p2.filter;
import java.io.File;
import java.io.FilenameFilter;
public class ShufflxFilter implements FilenameFilter {
private String suffix;
@Override
public boolean accept(File dir, String name) {
// TODO Auto-generated method stub
return name.endsWith(suffix);
}
public ShufflxFilter( String suffix) {
super();
this.suffix=suffix;
// TODO Auto-generated constructor stub
}
}
过滤文件的代码示例
package cn.itcast.p2.File.demo;
import java.io.File;
import cn.itcast.p2.filter.FilterByHadden;
import cn.itcast.p2.filter.ShufflxFilter;
public class FileListDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
// listDemo();
// listDemo_2();
listDemo_3();
}
private static void listDemo_3() {
// TODO Auto-generated method stub
File dir=new File("c:\\");
File[]files=dir.listFiles(new FilterByHadden());
for(File file:files) {
System.out.println(file);
}
}
private static void listDemo_2() {
// TODO Auto-generated method stub
File dir=new File("c:\\");
// String[]names=dir.list(new filterByName());//过滤器
String[]names=dir.list(new ShufflxFilter(".java"));//根据自定义后缀名过滤文件
for(String name:names)
{
System.out.println(name);
}
}
private static void listDemo() {
// TODO Auto-generated method stub
File file=new File("c:\\");
/*
* 获取当前目录的文件以及文件夹名称,包含隐藏文件
* 调用list方法的File对象中封装的必须是目录
* 否则会发生NullPointerException异常
* 如果访问的是系统级目录也会发生指针异常
* 如果目录存在但是没有内容,会返回一个数组,但是长度为0
*
* */
String[]names=file.list();//获取当前目录的文件以及文件夹名称,包含隐藏文件
for(String name:names)
{
System.out.println(name);
}
}
}
获取目录下的文件
package cn.itcast.p2.File.test;
import java.io.File;
/*
* 需求:对指定目录进行所有内容的列出(包含子目录中的内容)
* 也可以理解为深度遍历
*
* */
public class FileTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
File dir=new File("I:\\");
listAll(dir,0);
}
private static void listAll(File dir,int level) {
// TODO Auto-generated method stub
// 获取指定目录下当前的所有文件夹或者文件对象
File[]files=dir.listFiles();
for(int x=0;x<files.length;x++) {
if(files[x].isDirectory()) {
listAll(files[x],level);
}
else
System.out.println(getSpace(level)+files[x].getName());
}
}
private static String getSpace(int level) {
// TODO Auto-generated method stub
StringBuilder sb=new StringBuilder();
for(int x=0;x<level;x++) {
sb.append("|--");
}
return sb.toString();
}
}
删除目录下的文件
package cn.itcast.p2.File.test;
import java.io.File;
/*
* 删除一个带有内容的目录
* 原理:必须从最里面往外删
*
*
* */
public class RemoveDirTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
File dir=new File("");
// dir.delete();
removeDir(dir);
}
private static void removeDir(File dir) {
// TODO Auto-generated method stub
File[]files=dir.listFiles();
for(File file:files) {
if(file.isDirectory()) {
removeDir(file);
}else {
System.out.println(file+":"+file.delete());
}
}
System.out.println(dir+":"+dir.delete());
}
}
7 Properties
7.1 Properties基本操作
package cn.itcast.p2.properties;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
/*
* Map
* |--Hashtable
* |--Properties:
*
* Properties集合:
* 特点:
* 1、该集合中的键和值都是字符串类型
* 2、集合中的数据保存到流中,或者从流获取(字节流、字符流都行)
*
* 通常该集合用于操作以键值对形式存在的配置文件
*
*
*
* */
// propertiesDemo();
// methodDemo();
// methodDemo_2();
// methodDemo_3();
methodDemo_4();
}
private static void methodDemo_4() throws IOException {
// TODO Auto-generated method stub
// 对已有的配置文件中的信息进行修改
/*
* 读取这个文件
* 并将这个文件中的键值数据存储到集合中
* 再通过集合对数据进行修改
* 再通过流将修改后的数据存储到文件中
* */
File file=new File("info.txt");
if(!file.exists()) {
file.createNewFile();
}
FileReader fr=new FileReader(file);
// FileWriter fw=new FileWriter(file);//放到这个位置里面将只有wangwu=16这一条信息
// 创建集合存储配置信息
Properties prop=new Properties();
// 将流中信息存储到集合中
prop.load(fr);
prop.setProperty("wangwu", "16");
// 创建输出流
FileWriter fw=new FileWriter(file);//因为这个file也就是info.txt是新建的(覆盖了之前的info.txt),将集合中的所有信息输出到里头
// 将集合中的信息存储到输出流中
prop.store(fw, "modify wangwu");
fw.close();
fr.close();
}
private static void methodDemo_3() throws IOException {
// TODO Auto-generated method stub
Properties prop=new Properties();
// 集合中的数据来自于一个文件
// 注意:必须保证该文件中的数据是键值对
// 需要使用到读取流
FileInputStream fis=new FileInputStream("info.txt");
// 使用load方法
prop.load(fis);
prop.list(System.out);
}
private static void methodDemo_2() throws IOException {
// TODO Auto-generated method stub
Properties prop=new Properties();
// 存储元素
prop.setProperty("zhangsan", "30");
prop.setProperty("lisi", "31");
prop.setProperty("wangwu", "26");
prop.setProperty("zhaoliu", "20");
// 想要将这些集合中的字符串键值信息持久化存储到文件中
// 需要关联输出流
FileOutputStream fos=new FileOutputStream("info.txt");
// 将集合中数据存储到文件中,使用Store方法
prop.store(fos, "name+age");
fos.close();
}
private static void methodDemo() {
// TODO Auto-generated method stub
// 演示Properties集合和流对象相结合的功能
Properties prop=new Properties();
// 存储元素
prop.setProperty("zhangsan", "30");
prop.setProperty("lisi", "31");
prop.setProperty("wangwu", "26");
prop.setProperty("zhaoliu", "20");
prop.list(System.out);//将存储的元素打印输出到控制台
}
/*
* Properties集合的存和取
*
*
* */
private static void propertiesDemo() {
// TODO Auto-generated method stub
// 创建一个Properties集合
Properties prop=new Properties();
// 存储元素
prop.setProperty("zhangsan", "30");
prop.setProperty("lisi", "31");
prop.setProperty("wangwu", "26");
prop.setProperty("zhaoliu", "20");
// 修改元素
prop.setProperty("wangwu", "36");
// 取出所有元素
Set<String>names=prop.stringPropertyNames();
for(String name:names) {
String value=prop.getProperty(name);
System.out.println(name+":"+value);
}
}
}
7.2 Properties案例示例
package cn.itcast.p2.properties;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/*
* 获取指定目录下,指定扩展名的文件(包含子目录中的)
* 这些文件的绝对路径写入到一个文本文件中
*
* 简单的说,就是建立一个指定扩展名的文件的列表
*
* 思路:
* 1、必须进行深度遍历
* 2、要在遍历的过程中进行过滤,将符合条件的内容都存储到容器中
* 3、对容器中的内容进行遍历并将绝对路径写入到文件中
*
*
* */
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
File dir=new File("J:\\协同中心");
FilenameFilter filter=new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
// TODO Auto-generated method stub
return name.endsWith(".xlsx");
}
};
List<File>list=new ArrayList<File>();
getFiles(dir,filter,list);
File destfile=new File(dir,"javalist.txt");
writerToFile(list,destfile);
}
private static void getFiles(File dir,FilenameFilter filter,List<File>list) {
// TODO Auto-generated method stub
File[]files=dir.listFiles();
for(File file:files) {
if(file.isDirectory()) {
getFiles(file,filter,list);
}else {
// 对过滤器进行过滤,将符合条件的对象存储到集合中
if(filter.accept(dir, file.getName())) {
list.add(file);
}
}
}
}
public static void writerToFile(List<File>list,File destFile) {
BufferedWriter bufw=null;
try {
bufw=new BufferedWriter(new FileWriter(destFile));
for(File file:list) {
bufw.write(file.getAbsolutePath());
bufw.newLine();
bufw.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
throw new RuntimeException("写入失败");
}finally {
if(bufw!=null)
try {
bufw.close();
}catch(IOException e){
throw new RuntimeException("关闭失败");
}
}
}
}
package cn.itcast.p2.properties;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
/*
* 定义功能,获取一个应用程序运行的次数,如果超过5次,给出使用次数已到请注册的提示,并终止程序的运行
* 思路:
* 1、应该有计数器
* 每次程序启动都需要计数一次,并且是在原有的次数上进行计数
* 2、计数器就是一个变量,程序启动时进行计数,计数器必须存在于内存并进行运算
* 可是程序一结束,计数器就消失了,那么再次启动该程序,计数器又被重新初始化了
* 而我们需要多次启动同一个应用程序,使用的是同一个计数器
* 这就需要计数器的生命周期变长,从内存存储到硬盘文件中
* 3、如何使用计数器呢?
* 首先,程序启动时,应该先读取这个用于记录计数器信息的配置文件,获取上一次计数器次数
* 其次,对该次数进行自增,并将自增后的次数重新存储到配置文件中。
* 4、文件中的信息该如何进行存储并体现?
* 直接存储次数值可以,但是不明确该数据的含义。所以起名字变得很重要
* 这就有了名字和值的对应,所以可以使用键值对
* 映射关系可以使用map集合搞定,由于又需要读取硬盘上的数据,所以用map+io=properties搞定
*
* */
public class PropertiesTest {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
getAppCount();
}
private static void getAppCount() throws IOException {
// TODO Auto-generated method stub
// 将配置文件封装成File对象
File confile=new File("count.properties");
if(!confile.exists()) {
confile.createNewFile();
}
FileInputStream fis=new FileInputStream(confile);
Properties prop=new Properties();
prop.load(fis);
// 从集合中通过键获取次数
String value=prop.getProperty("time");
// 定义计数器,记录获取到的次数
int count=0;
if(value!=null) {
count=Integer.parseInt(value);
if(count>=5) {
System.out.println("使用次数已到,请注册");
throw new RuntimeException();
}
}
count++;
// 将改变后的次数重新存储到集合中
prop.setProperty("time", count+"");
FileOutputStream fos=new FileOutputStream(confile);
prop.store(fos, "");
fos.close();
fis.close();
}
}
8 其他流
8.1 打印流
package cn.itcast.p2.print.demo;
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class PrintDemo {
public static void main(String[] args) throws FileNotFoundException {
// TODO Auto-generated method stub
/*
* PrintStream:
* 1、提供了打印方法可以对多种数据类型值进行打印,并保持数据的表示形式
* 2、它不抛IOException
*
* 构造函数,接收三种类型的值:
* 1、字符串路径
* 2、File对象
* 3、字节输出流
*
* */
PrintStream out=new PrintStream("print.txt");
// out.write(97);//只将低8为转成字符写入进去
out.print(97);//将97先变成字符保持原样将数据打印到目的地
out.close();
}
}
package cn.itcast.p2.print.demo;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class PrintWriterDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
/*
* PrintWriter:字符打印流
* 构造函数参数:
* 1、字符串路径
* 2、File对象
* 3、字节输出流
* 4、字符输出流
*
* */
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
// PrintWriter out=new PrintWriter(System.out,true);//加了true可以自动刷新(相当于位置1的功能)
PrintWriter out=new PrintWriter(new FileWriter("out.txt"),true);//写入到文件中
String line=null;
while((line=bufr.readLine())!=null) {
if("over".equals(line))
break;
out.println(line.toUpperCase());
// out.flush();//位置1
}
out.close();
bufr.close();
}
}
8.2 序列流
package cn.itcast.p2.print.demo;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
public class SequenceInputStreamDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
/*
* 需求:将1.txt 2.txt 3.txt文件中的数据合并到一个文件中
*
* */
/*Vector<FileInputStream>v=new Vector<FileInputStream>();
v.add(new FileInputStream("1.txt"));
v.add(new FileInputStream("2.txt"));
v.add(new FileInputStream("3.txt"));
Enumeration<FileInputStream>en=v.elements();*/
// 上面方法也可,建议用下面的
ArrayList<FileInputStream>al=new ArrayList<FileInputStream>();
for(int x=1;x<=3;x++) {
al.add(new FileInputStream(x+".txt"));
}
Enumeration<FileInputStream>en=Collections.enumeration(al);//将列表转成枚举
SequenceInputStream sis=new SequenceInputStream(en);//序列流需传一个枚举
FileOutputStream fos=new FileOutputStream("4.txt");
byte[]buf=new byte[1024];
int len=0;
while((len=sis.read(buf))!=-1) {
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}
8.2.1 序列流案例示例
文件切割
package cn.itcast.io.p1.splitfile;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class SplitFileDemo {
private static final int SIZE = 1024*1024;
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//切割文件
File file=new File("J:\\01.mp3");
// splitFile(file);
// 文件切割+配置文件
splitFile_2(file);
}
private static void splitFile_2(File file) throws IOException{
// TODO Auto-generated method stub
// 用读取流关联源文件
FileInputStream fis=new FileInputStream(file);
// 定义一个1M的缓冲区
byte[]buf=new byte[SIZE];
// 创建目的
FileOutputStream fos=null;
int len=0;
int count=1;
/*
* 切割文件时,必须记录住被切割文件的名称,以及切割出来碎片文件的个数,以方便于合并。
* 这个信息为了进行描述,使用键值对的方式。用到了properties对象
*
* */
Properties prop=new Properties();
File dir=new File("J:\\partfiles");
if(!dir.exists())
dir.mkdirs();
while((len=fis.read(buf))!=-1) {
fos=new FileOutputStream(new File(dir,(count++)+".part"));
fos.write(buf,0,len);
fos.close();
}
// 将被切割文件的信息保存到prop集合中
prop.setProperty("partcount", count+"");
prop.setProperty("filename", file.getName());
fos=new FileOutputStream(new File(dir,count+".properties"));
// 将prop集合中的数据存储到文件中
prop.store(fos, "save file info");
fos.close();
fis.close();
}
private static void splitFile(File file) throws IOException {
// TODO Auto-generated method stub
// 用读取流关联源文件
FileInputStream fis=new FileInputStream(file);
// 定义一个1M的缓冲区
byte[]buf=new byte[SIZE];
// 创建目的
FileOutputStream fos=null;
int len=0;
int count=1;
File dir=new File("J:\\partfiles");
if(!dir.exists())
dir.mkdirs();
while((len=fis.read(buf))!=-1) {
fos=new FileOutputStream(new File(dir,(count++)+".part"));
fos.write(buf,0,len);
}
fos.close();
fis.close();
}
}
文件合并
过滤器
package cn.itcast.io.p1.splitfile;
import java.io.File;
import java.io.FilenameFilter;
public class SuffixFilter implements FilenameFilter {
private String suffix;
@Override
public boolean accept(File dir, String name) {
// TODO Auto-generated method stub
return name.endsWith(suffix);
}
public SuffixFilter(String suffix) {
super();
this.suffix = suffix;
}
}
合并
package cn.itcast.io.p1.splitfile;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
public class MergeFileDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//合并文件
File dir=new File("J:\\partfiles");
// mergeFile(dir);
mergeFile_2(dir);
}
private static void mergeFile_2(File dir) throws IOException {
// TODO Auto-generated method stub
// 获取指定目录下的配置文件对象
File[]files=dir.listFiles(new SuffixFilter(".properties"));
if(files.length!=1)
throw new RuntimeException(dir+",该目录下没有properties扩展名的文件或者不唯一");
// 记录配置文件对象
File confile=files[0];
// 获取该文件中的信息
Properties prop=new Properties();
FileInputStream fis=new FileInputStream(confile);
prop.load(fis);
String filename=prop.getProperty("filename");
int count=Integer.parseInt(prop.getProperty("partcount"));
// 获取该目录下的所有碎片文件
File[]partFiles=dir.listFiles(new SuffixFilter(".part"));
if(partFiles.length!=(count-1)) {
throw new RuntimeException("碎片文件不符合要求,个数不对!应该"+count+"个");
}
// 将碎片文件和流对象关联并存储到集合中
ArrayList<FileInputStream>al=new ArrayList<FileInputStream>();
for(int x=1;x<partFiles.length;x++) {
al.add(new FileInputStream(partFiles[x]));
}
// 将多个流合并成一个序列流
Enumeration<FileInputStream>en=Collections.enumeration(al);
SequenceInputStream sis=new SequenceInputStream(en);
FileOutputStream fos=new FileOutputStream(new File(dir,filename));
byte[] buf=new byte[1024];
int len=0;
while((len=sis.read(buf))!=-1) {
fos.write(buf, 0, len);
}
fos.close();
sis.close();
}
private static void mergeFile(File dir) throws IOException {
// TODO Auto-generated method stub
ArrayList<FileInputStream>al=new ArrayList<FileInputStream>();
for(int x=1;x<8;x++)
{
al.add(new FileInputStream(new File(dir,x+".part")));
}
Enumeration<FileInputStream>en=Collections.enumeration(al);
SequenceInputStream sis=new SequenceInputStream(en);
FileOutputStream fos=new FileOutputStream(new File(dir,"02.mp3"));
byte[] buf=new byte[1024];
int len=0;
while((len=sis.read(buf))!=-1) {
fos.write(buf, 0, len);
}
fos.close();
sis.close();
}
}
8.2.2 对象序列化和反序列化
Person类实现Serializable接口
package cn.itcast.io.p2.bean;
import java.io.Serializable;
/*
* Serializable用于给序列化的类加入ID号
* 用于判断类和对象是否是同一个版本
* transient:非静态数据不想被序列化可以使用这个关键字修饰
*
*
* */
public class Person implements Serializable/*标记接口*/{
private static final long serialVersionUID=95271;//如果不自定义这个ID的话,系统会根据类型等自动算出一个ID,但这个根据编译器版本算出有所差异,所以
//可能导致,在不同编译器下序列化的文件,在另一个版本编译器下不能被反序列化(序列化和反序列化的时候它需要校正这个ID)
//为此,如果你将某个对象序列化后,然后将这个类中的private String name;改成public String name它也不能被反序列化,ID号变了
private String name;
// private transient String name;//不会被序列化
// private static int age;//静态数据的值不会被序列化,比如这个反序列化回来就是0(它在静态去,对象在堆区)
private int 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;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
对象序列化和反序列化
package cn.itcast.io.p1.splitfile;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import cn.itcast.io.p2.bean.Person;
public class objectStreamDemo {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
// TODO Auto-generated method stub
writeObject();
readObject();
}
private static void readObject() throws FileNotFoundException, IOException, ClassNotFoundException {
// TODO Auto-generated method stub
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("obj.object"));
// 对象的反序列化
Person p=(Person)ois.readObject();
System.out.println(p.getName()+":"+p.getAge());
ois.close();
}
private static void writeObject() throws FileNotFoundException, IOException {
// TODO Auto-generated method stub
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("obj.object"));
// 对象序列化,被序列化的对象必须实现Serializable接口
oos.writeObject(new Person("小强",30));
oos.close();
}
}
9 其他流的读写
9.1 文件随机读写
package cn.itcast.io.p1.splitfile;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
/*
* RandomAccessFile不是io体系中的子类
* 特点:
* 1、该对象既能读又能写
* 2、该对象内部维护了一个byte数组,并通过指针可以操作数组中的元素
* 3、可以通过getFilePointer方法获取指针的位置,和通过seek方法设置指针的位置
* 4、其实该对象就是将字节输入流和输出流进行了封装
* 5、该对象的源和目的只能是文件(文本文件、媒体文件都可)
*
* */
writeFile();
readFile();
randomWrite();
}
private static void randomWrite() throws IOException {
// TODO Auto-generated method stub
RandomAccessFile raf=new RandomAccessFile("ranacc.txt","rw");
// raf.write("赵六".getBytes());//这样的话就覆盖了之前数组里的张三和102(因为文件存在,它不会重新创建,也就是该数组存在,只会覆盖)
// raf.writeInt(102);
// 往指定位置写入数据
raf.seek(5*8);//定位指针位置
raf.write("哈哈".getBytes());
raf.writeInt(108);
raf.close();
}
private static void readFile() throws IOException {
// TODO Auto-generated method stub
RandomAccessFile raf=new RandomAccessFile("ranacc.txt","r");
// 通过seek设置指针的位置
// raf.seek(1*8);//将指针移到第8个字节的位置
byte[]buf=new byte[6];//因为系统编码是utf-8,所以一个汉字是三个字节存储的,为此这里是6,如果变成4,则后面那个字是乱码
raf.read(buf);
String name=new String(buf);
int age=raf.readInt();
System.out.println("name="+name);
System.out.println("age="+age);
System.out.println("pos:"+raf.getFilePointer());//获取指针当前位置
raf.close();
}
// 使用RandomAccessFile对象写入一些人员信息,比如姓名和年龄
private static void writeFile() throws IOException {
// TODO Auto-generated method stub
//如果文件不存在,则创建,如果文件存在,不创建
RandomAccessFile raf=new RandomAccessFile("ranacc.txt","rw");
raf.write("张三".getBytes());//写入的是字节
// raf.write(97);//只写低8位
raf.writeInt(908);//都写入
raf.close();
}
}
9.2 基本数据类型的读写
package cn.itcast.io.p3.dataStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataStreamDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
// 操作基本数据类型的流
writeData();
readData();
}
private static void readData() throws IOException {
// TODO Auto-generated method stub
DataInputStream r=new DataInputStream(new FileInputStream("data.txt"));
System.out.println(r.readUTF());
r.close();
}
private static void writeData() throws IOException {
// TODO Auto-generated method stub
DataOutputStream dis =new DataOutputStream(new FileOutputStream("data.txt"));
dis.writeUTF("你好");//修改版的utf-8,前面有一个标识符
dis.close();
}
}
9.3 字节数组读写
package cn.itcast.io.p3.byteStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
public class byteStreamDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
ByteArrayInputStream bis=new ByteArrayInputStream("abcd".getBytes());
ByteArrayOutputStream bos=new ByteArrayOutputStream();
int len=0;
while((len=bis.read())!=-1) {
bos.write(len);
}
System.out.println(bos.toString());
}
}
9.4 管道流读写
package cn.itcast.io.p1.piped;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class pipedDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
PipedInputStream input=new PipedInputStream();
PipedOutputStream output=new PipedOutputStream();
input.connect(output);//输入流连接输出流
new Thread(new Input(input)).start();
new Thread(new Output(output)).start();
}
}
class Input implements Runnable{
private PipedInputStream in;
Input(PipedInputStream in){
this.in=in;
}
public void run() {
try {
byte[]buf=new byte[1024];
int len=in.read(buf);
String s=new String(buf,0,len);
System.out.println("s="+s);
in.close();
}catch(Exception e) {
}
}
}
class Output implements Runnable{
private PipedOutputStream out;
Output(PipedOutputStream out){
this.out=out;
}
public void run() {
try {
out.write("hi,管道来了".getBytes());
}catch(Exception e) {
}
}
}
10. 编码解码
10.1 编码解码解析
package cn.itcast.io.p4.encode;
import java.io.UnsupportedEncodingException;
public class EncodeDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
// TODO Auto-generated method stub
/*
* 字符串--->字节数组:编码
* 字节数组--->字符串:解码
*
* */
String str="你好";
// 编码
byte[]buf=str.getBytes();
// byte[]buf=str.getBytes("GBK");//指定为GBK编码
// printBytes(buf);
// 解码
String s1=new String(buf);//默认方式解码
// String s1=new String(buf,"utf-8");//指定码表解码
System.out.println("s1="+s1);
errorEncode();
}
private static void errorEncode() throws UnsupportedEncodingException {
// TODO Auto-generated method stub
/*
* 如果编码编错了,解不出来
* 如果编码对了,解错了,有可能有救
* */
String str="你好";
byte[]buf=str.getBytes();
String s1=new String(buf,"iso8859-1");//编码是utf-8,用iso8859-1解码
System.out.println("s1="+s1);//结果:s1=ä½ å¥½
byte[]buf2=s1.getBytes("iso8859-1");//获取源字节
String s2=new String(buf2,"utf-8");
System.out.println("s2="+s2);
}
private static void printBytes(byte[] buf) {
// TODO Auto-generated method stub
for(byte b:buf) {
System.out.println(b);
}
}
}
10.2 编码解码案例
package cn.itcast.io.p4.encode;
import java.io.UnsupportedEncodingException;
public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
// TODO Auto-generated method stub
/*
* 在java中,字符串"abcd"与字符串"ab你好"的长度是一样,都是四个字节。
* 但对应的字节数不同,一个汉字占两个字节
* 定义一个方法,按照最大的字节数来取字串
* 如:对于"ab你好",如果取三个字节,那么子串就是ab与"你"字的半个
* 那么半个就要舍弃,如果取四个字节就是"ab你",取五个字节还是"ab你"
*
* */
String str="ab你好cd谢谢";
int len=str.getBytes("GBK").length;
for(int x=0;x<len;x++) {
System.out.println("截取"+(x+1)+"个字节结果是:"+cutStringByte(str,x+1));
}
}
private static String cutStringByte(String str,int len) throws UnsupportedEncodingException {
// TODO Auto-generated method stub
byte[]buf=str.getBytes("GBK");
int count=0;
for(int x=len-1;x>=0;x--) {
if(buf[x]<0)
count++;//计算汉字的字节码数
else
break;
}
if(count%2==0)
return new String(buf,0,len,"gbk");//将buf里的从0到len长度的字节码按GBK解码
else
return new String(buf,0,len-1,"gbk");
}
}
上一篇: java获取日期之间天数的方法