java IO
此文档为java IO的学习总结
文件输入与输出
- 1.从文件中读取信息
//从文件中读取数据信息并打印输出
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Scanner; //三个包不能少
public class Test {
public static void main(String args[]) throws IOException //这个throws不能少
{
Scanner in = new Scanner(Paths.get("d:\\1.txt"));
String data = in.nextLine();
String data2 = in.nextLine();
System.out.println(data + '\n' + data2);
}
}
- 2.写入数据信息到文件中
//向文件中写入数据信息
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner; //三个包不能少
public class Test {
public static void main(String args[]) throws IOException //这个throws不能少
{
PrintWriter out = new PrintWriter("d:\\2.txt");
out.println("hahahaha"); //写入数据信息到指定文件
out.flush(); //刷新文件
}
}
Java IO: 管道
由于java语言的stream严格区分为inputstream和outputstream,流数据读写之间转换一般使用临时文件方式来转换,但是这种方式使用的效率比较低,因此可以使用管道来实现,java管道支持比较弱,需要多线程来支持,
import org.junit.Test;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/**
* FileName: TestPipe
* Author: braincao
* Date: 2018/10/4 15:23
* Description: 两个线程间用管道实现通信的例子
* Java IO中的管道为运行在同一个JVM中的两个线程提供了通信的能力
*/
public class TestPipe {
@Test
public void test1() throws IOException{
PipedOutputStream output = new PipedOutputStream();
PipedInputStream input = new PipedInputStream(output);
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try{
output.write("hello world".getBytes());
output.close(); //通信完切记关闭管道资源
}catch(IOException e){
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try{
int data = input.read();
while(data!=-1){
System.out.print((char)data + " ");
data = input.read();
}
input.close();//通信完切记关闭管道资源
}catch(IOException e){
e.printStackTrace();
}
}
});
thread1.start();
thread2.start();
}
}
//out:h e l l o w o r l d
java IO
1.File类: 文件或目录路径(文件夹)的抽象表示形式。通过File对象可以访问文件的属性、创建空文件和目录
@Test
public void test1() throws IOException, InterruptedException{
//创建目录路径(文件夹)--mkdir():如果父目录不存在,失败
String path2 = "/Users/braincao/git/test";
File file2 = new File(path2);
boolean flag = file2.mkdir();
System.out.println(flag);
//创建目录路径(文件夹)--mkdirs():如果父目录不存在,一同创建
String path = "/Users/braincao/git/test/test";
File file3 = new File(path);
boolean flag3 = file3.mkdirs();
System.out.println(flag3);
//创建文件--createNewFile()
File file = new File("/Users/braincao/git/2.txt");
if(!file.exists()){ //如果不存在则创建新文件,存在就不创建
file.createNewFile();
}
// if(file.exists()){
// file.delete();//如果存在则删除文件,不存在就不创建
// }
//创建临时文件,程序退出即删除
File tmp = File.createTempFile("test", ".temp", new File("/Users/braincao/git"));
Thread.sleep(2000);//放大延时便于观看效果
tmp.deleteOnExit();//文件退出即删除
//输出当前系统的根目录--listRoots()
File[] roots = File.listRoots(); //当前系统的根目录
}
@Test
public void test2(){
//遍历文件夹中的文件--String[] list()
File file4 = new File("/Users/braincao/git");
if(file4.isDirectory()){ //如果是目录路径
String[] lists = file4.list(); //返回的是文件夹中所有东西的路径字符串,不是File对象
for(String s: lists){
System.out.println(s);
}
System.out.println("=========");
File[] files = file4.listFiles();//返回的是文件夹中所有东西的File对象
for(File f: files){
System.out.println(f.getName());
}
System.out.println("=========");
//命令设计模式
//FilenameFilter()--设置过滤模板,显示想要的文件或路径
File[] ff = file4.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return new File(dir, name).isFile() && name.endsWith(".txt"); //返回后缀.txt的文件(非路径)
}
});
for(File f: ff){
System.out.println(f.getName());
}
}
}
输出子孙级目录的绝对路径名称—递归
static void test3(String path) throws Exception{
/**
* @Description: 输出子孙级目录的绝对路径名称---递归
*/
File file = new File(path);
if(file.isFile()){
System.out.println(file.getAbsolutePath());
return;
}
File[] ff = file.listFiles();
for(File f: ff){
if(f.isFile()){
System.out.println(f.getAbsolutePath());
}
else{
test3(f.getAbsolutePath());
}
}
}
public static void main(String[] args) throws Exception{
test3("/Users/braincao/git/test");
}
2.IO:
- 节点流:节点流处于IO操作的第一线,所有操作必须通过它们进行
字节流
字符流
- 处理流:处理流可以对其他流进行处理(增强功能,提高效率)
字节流:二进制流,可以处理一切文件,包括纯文本、doc、音频、视频等等
输入流:InputStream--read(byte[] b)、read(byte[] b, int off, int len)、close()
FileInputStream()
输出流:OutputStream--write(byte[] b)、write(byte[] b, int off, int len)、flush()、close()
FileOutputStream()
字符流:文本流,只能处理纯文本
输入流:Reader--read(char[] cbuf)、read(char[] cbuf, int off, int len)、close()
FileReader()
输出流:Writer--write(char[] cbuf)、write(String[] str, int off, int len)、write(char[] cbuf, int off, int len)、flush()、close()
FileWriter()
2.1字节流
读取文件input、写入文件output的demo
@Test
public void input(){
/**
* @Description: 读取文件
* 1.建立联系:File对象
2.选择流:字节输入流:InputStream FileInputStream
3.操作:数组大小byte[] b = new byte[1024]、read、write
4.释放资源
*/
//1.建立联系
File file = new File("/Users/braincao/git/1.txt");
//2.选择流,这里有异常需要try catch
InputStream input = null; //提升作用域便于后面释放资源
try {
input = new FileInputStream(file);
//3.操作:不断读取
byte[] b = new byte[10]; //每次最多读取10字节的缓冲数组
int len = 0;//每次读取的真实字节长度
//循环读取
while(-1 != (len=input.read(b))){
//输出,需要将字节数组转成String
String str = new String(b, 0, len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(input!=null){
try {
input.close(); //释放资源
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void output(){
/**
* @Description: 写出文件
* 1.建立联系:File对象
2.选择流:字节输出流:OutputStream FileOutputStream
3.操作:write、flush、close
4.释放资源
*/
//1.建立联系
File file = new File("/Users/braincao/git/2.txt");
//2.选择流
OutputStream output = null;//提升作用域便于后面释放资源
try {
output = new FileOutputStream(file, true);//true是追加写入,false是覆盖写入
String str = "hello world!\n";
//将String转成byte数组
byte[] b = str.getBytes();
try {
output.write(b, 0, b.length); //3.操作:写入文件
output.flush(); //强制刷新出去。如果没有强制刷新,IO管道满了或者需要等到释放资源时,才会flush推出写入。因此要养成手动flush的习惯
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(output!=null){
try {
output.close(); //释放资源
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
#####拷贝文件、拷贝文件夹
拷贝文件:实现文件拷贝。结合了输入流input和输出流output,边读取边写入
拷贝文件夹
1.递归查找子孙级文件/文件夹
2.文件:IO流复制;文件夹:创建并递归下一级
@Test
public static void copy(String pathSrc, String pathDest) throws IOException {
/**
* @Description: 实现文件拷贝。结合了输入流input和输出流output,边读取边写入
* 1.建立联系:File对象
2.选择流:字节输入流:InputStream FileInputStream
字节输出流:OutputStream FileOutputStream
3.操作:数组大小byte[]+read
write
flush+close
4.释放资源
*/
//1.建立联系
File fileSrc = new File(pathSrc);
File fileDest = new File(pathDest);
//2.选择流
InputStream input = null;
OutputStream output = null; //提升作用域便于后面释放资源
try {
input = new FileInputStream(fileSrc);
output = new FileOutputStream(fileDest);
byte[] b = new byte[1024]; //读取与写入缓冲数组
int len = 0;
while(-1 != (len=input.read(b))){ //读取
try {
output.write(b, 0, len); //写入
} catch (IOException e) {
e.printStackTrace();
}
}
output.flush();//强制刷新出去
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally{
try {
if(input!=null){
input.close();
}
if(output!=null){
output.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public static void copyFileDir(String pathSrc, String pathDest){
/**
* @Description: 文件夹拷贝,递归实现
* 1.递归查找子孙级文件/文件夹
* 2.文件:IO流复制;文件夹:创建并递归下一级
*/
//1.建立联系
File fileSrc = new File(pathSrc);
File fileDest = new File(pathDest + File.separator + fileSrc.getName());
if(fileSrc.isFile()){//如果是文件,IOcopy
System.out.println("====file");
try {
if(!fileDest.exists()){
copy(fileSrc.getAbsolutePath(), fileDest.getAbsolutePath());
}
} catch (IOException e) {
e.printStackTrace();
}
}
else if(fileSrc.isDirectory()){ //如果是文件夹路径,创建路径并递归遍历
System.out.println("====fileDir");
if(!fileDest.exists()){
fileDest.mkdir(); //创建文件夹路径
System.out.println("chuangjianchenggong ");
}
File[] ff = fileSrc.listFiles();
for(File f: ff){
copyFileDir(f.getAbsolutePath(), fileDest.getAbsolutePath());
}
}
}
public static void main(String[] args) throws Exception{
//文件拷贝: IO流
//copy("/Users/braincao/git/1.txt", "/Users/braincao/git/2.txt");
/*文件夹拷贝: 文件->IO流复制;文件夹->创建路径并递归
*最终是把/Users/braincao/git/test文件夹拷贝到了/Users/braincao/git/test2/test中
*/
copyFileDir("/Users/braincao/git/test", "/Users/braincao/git/test2");
}
2.2 字符流
只能处理纯文本,全部为可见字符。
读取:Reader FileReader
写入:Writer FileWriter
@Test
public void charInputStream() throws IOException {
/**
* @Description: 字符流。从文本读取
* 1.建立联系:File对象
2.选择流:字符输入流:Reader FileReader
3.操作:数组大小char[] b = new byte[1024]、read、close
4.释放资源
*/
//1.建立联系
File src = new File("/Users/braincao/git/1.txt");
Reader r = null;
//2.选择流
try {
r = new FileReader(src);
//3.操作
char[] cbuf = new char[10];
int len = 0;
while(-1 != (len=r.read(cbuf))){
String ss = new String(cbuf, 0, cbuf.length);
System.out.println(ss);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
finally {
if(r!=null){
r.close();
}
}
}
@Test
public void charOutputStream() throws IOException {
/**
* @Description: 字符流。写入文本到文件
* 1.建立联系:File对象
2.选择流:字符输入流:Writer FileWriter
3.操作:write、flush、close
4.释放资源
*/
//1.建立联系
File dest = new File("/Users/braincao/git/2.txt");
//2.选择流
Writer w = null;
try {
w = new FileWriter(dest, true);//true追加;false覆盖
//3.操作
String data = "asdadasdasdqweasd";
w.write(data);
w.append("\nsada");
w.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
finally {
if(w!=null){
w.close();
}
}
}
3.处理流:在节点流之上,处理流可以对其他流进行处理(增强功能,提高效率)
为什么要有缓冲流?
比如说,家里盖房子,有一堆砖头要搬在工地100米外,单字节的读取就好比你一个人每次搬一块砖头,从堆砖头的地方搬到工地,这样可定很费时间,然后好的方法就是多叫几个小伙伴帮你一起搬砖头,这样因为人多了,每次可以搬十块砖头,但效率还是很低,这就好比我们的字节/字符数组读写操作;然而聪明的人类会用小推车,每次先搬砖头搬到小车上,再利用小推车运到工地上去,这样你或者你的小伙伴们再从小推车上取砖头是不是方便多了呀!这样效率就会大大提高,缓冲流就好比我们的小推车;给砖头暂时提供一个可存放的空间;
针对字节的处理流:字节缓冲流
- BufferedInputStream–直接把缓冲流加在字节流上就行,其他与字节流完全一样
- BufferedOutputStream–建议今后都加上缓冲流,提高性能
针对字符流的处理流:字符缓冲流
- BufferedReader 新增readLine()
- BufferedWriter 新增newLine()
字节缓冲流demo:
@Test
public static void copy(String pathSrc, String pathDest) throws IOException {
/**
* @Description: 字节缓冲流--拷贝文件demo
* 缓冲流直接加在字节流上
*/
//1.建立联系
File fileSrc = new File(pathSrc);
File fileDest = new File(pathDest);
//2.选择流
InputStream input = null;
OutputStream output = null; //提升作用域便于后面释放资源
try {
input = new BufferedInputStream(new FileInputStream(fileSrc));//缓冲流直接加在字节流上
output = new BufferedOutputStream(new FileOutputStream(fileDest));
byte[] b = new byte[1024]; //读取与写入缓冲数组
int len = 0;
while(-1 != (len=input.read(b))){ //读取
try {
output.write(b, 0, len); //写入
} catch (IOException e) {
e.printStackTrace();
}
}
output.flush();//强制刷新出去
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally{
try {
if(input!=null){
input.close();
}
if(output!=null){
output.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符缓冲流demo:
在字符流上加缓冲流。有新增方法readline()、newLine()
@Test
public static void bufferedCharCopy(String pathSrc, String pathDest) throws IOException {
/**
* @Description: 字符流,拷贝文本文件。在字符流上加缓冲流。有新增方法readline()、newLine()
*/
//1.建立联系
File src = new File(pathSrc);
File dest = new File(pathDest);
//2.选择流
Reader r = null;
Writer w = null;
try {
r = new BufferedReader(new FileReader(src)); //在字符流上加了缓冲流。有新增方法readLine()
w = new BufferedWriter(new FileWriter(dest)); //在字符流上加了缓冲流。有新增方法newLine()
// //3.1 读取写入操作
// char[] cbuf = new char[10];
// int len = 0;
// while(-1 != (len=r.read(cbuf))){
// w.write(cbuf, 0, cbuf.length);
// }
//3.2. 读取写入操作--用缓冲流的新增方法readLine()、newLine()
String line = null;
while(null != (line=((BufferedReader) r).readLine()) ){ //这里用缓冲流的新增方法,不能使用多态
w.write(line);
((BufferedWriter) w).newLine();
}
w.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
finally {
if(r!=null){
r.close();
}
if(w!=null){
w.close();
}
}
}
public static void main(String[] args) throws IOException {
bufferedCharCopy("/Users/braincao/git/1.txt", "/Users/braincao/git/2.txt");
}
转换流:将字符流转为字节流,将字节流转为字符流—>处理乱码(编码集、解码集)
字符 –编码集–> 二进制
字符 <–解码集– 二进制
出现乱码原因:
- 1.编解码字符集不统一
- 2.字节缺少,长度缺失(一个中文字符需要两个字节,少一个字节就乱码)
编解码例子:
@Test
public void test1() throws UnsupportedEncodingException {
/**
* @Description: 编解码例子,idea平台默认utf-8编解码
*/
String str = "中国"; //utf-8解码(将二进制解码成了"中国")
byte[] b1 = str.getBytes(); //utf-8编码(将字符串"中国"编码成了utf-8)
byte[] b2 = str.getBytes("gbk"); //gbk编码(将字符串"中国"编码成了gbk)
System.out.println(new String(b1,"utf-8")); //解码
System.out.println(new String(b1,"gbk")); //解码
System.out.println(new String(b2,"utf-8")); //解码
System.out.println(new String(b2,"gbk")); //解码
/*out:
中国
涓浗
�й�
中国
*/
}
转换流:
//输入流(字节流-->字符流):InputStreamReader 解码
//输出流:OutputStreamWriter(字节流-->字符流) 编码
@Test
public static void bufferedCharCharsetCopy(String pathSrc, String pathDest) throws IOException {
/**
* @Description: 当出现乱码问题时,使用转换流(字节流<--->字符流)
* 输入流:InputStreamReader 解码
输出流:OutputStreamWriter 编码
* 本例中:目的是:使用字符流进行文件拷贝
* 源文件(已知是gbk编码的二进制文件),我们想用字符流(直接用会出现乱码)
因此先用字节流,再用转换流将字节流转成字符流(解决编码问题的字符流)
同时最后还是加上一层缓冲字符流
*/
//
File src = new File(pathSrc);
File dest = new File(pathDest);
//BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(src), "utf-8")); //指定解码集,error乱码,源文件是gbk因此解码必须是gbk
//BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(src), "gbk")); //指定解码集,ok
//BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest), "gbk")); //指定编码集,ok
//BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(src), "gbk")); //指定解码集,ok
//BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest), "utf-8")); //指定编码集,ok
BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(src), "gbk")); //指定解码集,ok
BufferedWriter w = new BufferedWriter(new FileWriter(dest)); //不指定编码集,直接用字符流就行,也ok
String line = null;
while (null != (line = r.readLine())) {
System.out.println(line); //输出解码后的文本
w.write(line);
w.newLine();
}
w.flush();
w.close();
r.close();
}
public static void main(String[] args) throws IOException {
bufferedCharCharsetCopy("/Users/braincao/git/1.txt", "/Users/braincao/git/2.txt");
}
其他流:
字节数组流:将传入的File对象换成了byte[]数组,其他一样
输入流:ByteArrayInputStream bArray = new ByteArrayInputStream(byte [] a);
输出流:ByteArrayOutputStream bOut = new ByteArrayOutputStream();
byte[] dest = bOut.toByteArray() //这点不太一样,要用这种方式传给接受数组dest
基础数据类型处理流:基本类型+String,保留数据+类型
输入流:DataInputStream readXxx()
输出流:DataOutputStream writeXxx()
引用类型(对象)处理流:保留数据+类型,就是序列化、反序列化。通俗讲就是把对象序列化保存到文件中,再从文件中反序列化拿出对象
反序列化(输入流): ObjectInputStream readObject()
序列化(输出流): ObjectOutputStream writeObject()
注意:
先序列化后反序列化,反序列化顺序必须与序列化顺序一致
不是所有对象都可以序列化,对象所在类要实现java.io.Serializable接口(空接口让JVM识别)
每个对象有很多属性,不是所有属性都需要序列化,只序列化目标属性即可。transient
序列化反序列化Demo:
import java.io.*;
/**
* @FileName: EmployeeDemo
* @Author: braincao
* @Date: 2018-10-07 11:35:10
* @Description: 序列化反序列化demo
*/
class Employee implements java.io.Serializable{
private String name;
private transient int id; //transient标识,不让属性序列化
public Employee(String name, int id) {
this.name = name;
this.id = id;
}
public Employee() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
public class EmployeeDemo{
public static void main(String[] args) throws IOException, ClassNotFoundException {
Employee e = new Employee("张三", 2017111110);
//序列化
File outfile = new File("/Users/braincao/git/2.txt");
ObjectOutputStream os = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(outfile)));
os.writeObject(e);
os.close();
//反序列化
File infile = new File("/Users/braincao/git/2.txt");
ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(new FileInputStream(infile)));
Object obj = is.readObject();
if(obj instanceof Employee){
Employee tmp = (Employee)obj;
System.out.println(tmp.getName());
System.out.println(tmp.getId()); //transient修饰的属性不可见
}
is.close();
//out:张三 0
}
}
打印流:
System.out.println(“hello world”);中的out定义public final static PrintStream out = null;
,可见out就是PrintStream打印流
demo1:
import java.io.*;
public class PrintDemo {
public static void main(String[] args) throws IOException {
/**
* @Description: 打印流PrintStream(OutputStream out)demo
*/
//1.创建源
String ss = "锄禾日当午,汗滴禾下土";
//2.选择流
PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File("/Users/braincao/git/2.txt"))));
//3.操作
ps.write(ss.getBytes());
//4.释放资源
ps.close();
}
}
demo2:
import java.io.*;
import java.util.Scanner;
public class PrintDemo {
public static void test1() throws IOException {
/**
* @Description: 打印流PrintStream(OutputStream out)demo
* 输出到文件
*/
//1.创建源
String ss = "锄禾日当午,汗滴禾下土";
//2.选择流
PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File("/Users/braincao/git/2.txt"))));
//3.操作
ps.write(ss.getBytes());
//4.释放资源
ps.close();
}
public static void test2() throws FileNotFoundException {
/**
* @Description:三个常量
* System.in --输入流InputStream,默认是从键盘输入
* System.out --输出流OutputStream,默认是控制台输出
* System.err(与System.out一样,就是输出颜色不同)
*/
//输出流
System.out.println("asd");
System.err.println("asd");
//输入流1
InputStream is = System.in; //输入流,键盘输入
Scanner sc = new Scanner(is); //获取键盘输入的输入流
System.out.println(sc.nextLine());
//输入流2
BufferedInputStream fs = new BufferedInputStream(new FileInputStream(new File("/Users/braincao/git/2.txt")));
Scanner sc2 = new Scanner(fs); //获取文件输入的输入流
System.out.println(sc2.nextLine());
}
public static void test3() throws FileNotFoundException {
/**
* @Description:将System.in、System.out重定向,不再使用默认的键盘输入、控制台输出
* 重新分配“标准”输入/出流:System类方法:setIn(InputStream in)、setOut(PrintStream out)、setErr(PrintStream err)
*/
PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File("/Users/braincao/git/2.txt"))), true);//autoFlush设为true,如果不加一定要手动flush
System.setOut(ps); //重定向输出流
System.out.println("哈哈1234"); //直接写入到文件
ps.flush();
ps.close();
/**
* @Description:重定向后又想重新设为控制台
* FileDescriptor.in 键盘输入
* FileDescriptor.out 控制台输出
*/
ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)),true);
System.setOut(ps); //重定向输出流
System.out.println("哈哈1234");
}
public static void main(String[] args) throws IOException {
//test1();
//test2();
test3();
}
}
装饰设计模式
IO流用到的就是装饰设计模式,包装后增强功能
/**
* @FileName: Decrator
* @Author: braincao
* @Date: 2018/10/7 16:29
* @Description: 装饰设计模式Demo---扩音器例子。IO流用到的就是装饰设计模式,包装后增强功能
*/
class Voice{
private int voice = 10; //初始音量为10
public Voice() {
}
public void say(){
System.out.println(voice); //播放声音,音量为10
}
public int getVoice() {
return voice;
}
public void setVoice(int voice) {
this.voice = voice;
}
}
class Amplify{
private Voice voice;
public Amplify(Voice voice) {
this.voice = voice;
}
public void say(){
System.out.println(voice.getVoice()*100); //放大音量,现在为1000
}
public Voice getVoice() {
return voice;
}
public void setVoice(Voice voice) {
this.voice = voice;
}
}
public class Decrator {
public static void main(String[] args){
Voice v = new Voice();
v.say(); //音量为10
Amplify am = new Amplify(v);
am.say(); //音量为1000
}
}
文件分割与合并Demo1
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
import java.io.*;
/**
* @Description: 文件分割与合并的demo
*/
public class TestDemo {
public static void main(String[] args) throws IOException {
File fileSplit = new File("/Users/braincao/git/test/xiezhu_pub.rar"); //要分割的文件,分割后存放的目录也在同级目录中
File fileMerge = new File("/Users/braincao/git/test"); //存放分割文件的目录,合并后的文件也存在此目录中
// split(fileSplit);
merge(fileMerge);
}
//文件分割
public static void split(File file) throws IOException {
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = null;
byte[] buf = new byte[1024*1024]; //每个分割文件的大小
int len = 0;
int count = 1;
while(-1 != (len=fis.read(buf))){
fos = new FileOutputStream(new File(file.getParent(), count+".part"));
count++;
fos.write(buf, 0, len);
fos.flush();
}
fis.close();
//输出写入配置文件
Properties prop = new Properties();
fos = new FileOutputStream(new File(file.getAbsoluteFile() + ".properties" ));
prop.setProperty("fileName", file.getName());
prop.setProperty("partCount", (count-1)+"");
prop.store(fos,"save file info");
fos.close();
}
//文件合并
public static void merge(File file) throws IOException{
//1.拿到properties中的相关信息
File[] propFiles = file.listFiles(new SuffixFilter(".properties"));
if(propFiles.length!=1){
throw new RuntimeException(file+"该目录下没有properties扩展名的文件或者不唯一");
}
Properties pp = new Properties();
FileInputStream propInput = new FileInputStream(propFiles[0]);
pp.load(propInput);
String fileName = pp.getProperty("fileName");
int partNum = Integer.parseInt(pp.getProperty("partCount"));
//2.遍历目录中.part文件,用SequenceInputStream输入流组合
ArrayList<FileInputStream> fis = new ArrayList<>();
File[] files = file.listFiles(new SuffixFilter(".part"));
for(int i=0; i<files.length; ++i){
fis.add(new FileInputStream(files[i]));
}
Enumeration<FileInputStream> efis = Collections.enumeration(fis);
SequenceInputStream sis = new SequenceInputStream(efis);
//3.输入流:SequenceInputStream;输出流:FileOutputStream--->拷贝写入
FileOutputStream fos = new FileOutputStream(new File(file.getAbsolutePath(), "Merge_" + fileName));
byte[] b = new byte[1024*1024];
int len = 0;
while(-1 != (len=sis.read(b))){
fos.write(b, 0, len);
fos.flush();
}
fos.close();
sis.close();
}
}
class SuffixFilter implements FilenameFilter{
private String suffix;
public SuffixFilter(String suffix){
super();
this.suffix = suffix;
}
@Override
public boolean accept(File dir, String name) {
return name.endsWith(suffix);
}
}
文件分割与合并Demo2(这个包含很多知识点,建议详看)
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
/**
* @FileName: RandomAccessFileDemo
* @Author: braincao
* @Date: 2018/10/7 16:52
* @Description: 文件分割与合并Demo
* 文件分割思路:
* 1.确定每一块的大小 blockSize
* 2.已知文件总大小length和blockSize,计算确定分割的块数 n=Math.ceil(length/blockSize) //Math.ceil(double a)返回大于等于a的最小整数(返回double类型)
* 3.确定最后一块的大小 length - (n-1)*blockSize
*/
public class SplitFileDemo {
private String filePath; //源文件路径
private String fileName; //源文件名
private long length; //源文件名
private String destPath; //分割后文件存放目录
private long blockSize; //每块的大小
private List<String> blockPath; //每块的名称
private int n; //分割的块数
public SplitFileDemo(String filePath, String destPath){
this(filePath, destPath, 10);
}
public SplitFileDemo(String filePath, String destPath, long blockSize){
blockPath = new ArrayList<>();
this.filePath = filePath;
this.destPath = destPath;
this.blockSize = blockSize;
init(); //初始化各项参数
}
private void init(){
/**
* @Description: 初始化操作:修正每块大小、计算块数、确定文件名
*/
File src = null;
//健壮性
if(null==filePath || !(src=new File(filePath)).exists() || !(src.isFile()) ){
return;
}
//文件名
this.fileName = src.getName();
//修正每块大小、计算块数
this.length = src.length(); //文件实际大小
if(this.blockSize > length){//修正每块大小
this.blockSize = length;
}
//确定块数
n = (int)Math.ceil(length*1.0/this.blockSize); //Math.ceil(double a)返回大于等于a的最小整数,返回double类型
initPathName(destPath);
}
private void initPathName(String destPath){//确定文件名
for(int i=0; i<n; ++i){
blockPath.add(destPath + "/" + fileName + ".part" + i);
}
}
//文件分割
public void split(){
/**
* @Description: 上面都是为文件分割做准备,现在开始分割
* @Param: [destPath] 分割文件存放的目录
* 文件分割:
* 第几块、起始位置、实际大小
*/
long beginPos = 0; //起始点
long actualBlockSize = blockSize; //实际大小
for(int i=0; i<n; ++i){
if(i==n-1){
actualBlockSize = this.length-beginPos;
}
splitDetail(i, beginPos, actualBlockSize);
beginPos += actualBlockSize;
}
}
private void splitDetail(int blockNum, long beginPos, long actualBlockSize){
/**
* @Description:文件分割的具体操作,其实就是文件拷贝过程
* 输入流:RandomAccessFile
* 输出流: FileOutputStream
* @Param: [blockNum, beginPos, actualBlockSize] 第几块、起始点、实际每块大小(主要针对最后一块)
*/
//1.创建源
File src = new File(this.filePath);
File dest = new File(this.blockPath.get(blockNum));
//2.选择流
RandomAccessFile rnd = null;//参数"r"只读
BufferedOutputStream fo = null;
try {
rnd = new RandomAccessFile(src, "r");
fo = new BufferedOutputStream(new FileOutputStream(dest));
//3.操作
rnd.seek(beginPos); //从beginPos位置开始读取文件
byte[] b = new byte[1024]; //定义缓冲区
int len = 0;//实际读取长度
//目标:从文件beginPos位置读取actualBlockSize大小的东西,每次实际读取len大小
while(-1 != (len=rnd.read(b))){
if(len<actualBlockSize){
fo.write(b, 0, len); //写入文件
fo.flush();
actualBlockSize -= len;
}
else{//最后一块了
fo.write(b, 0, (int)actualBlockSize); //写入文件
fo.flush();
break;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(rnd!=null){
rnd.close();
}
if(fo!=null){
fo.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//文件合并--法1
public void mergeFile(String destPath) {
/**
* @Description:文件合并的具体操作,其实就是文件拷贝过程
* 输入流:FileInputStream
* 输出流: FileOutputStream
* @Param: [destPath] 合并后文件的存放目录
*/
File dest = new File(destPath);
BufferedOutputStream fo = null;
try {
fo = new BufferedOutputStream(new FileOutputStream(dest,true));
for (int i = 0; i < blockPath.size(); ++i) {
//1.创建源
File src = new File(this.blockPath.get(i));
//2.选择流
BufferedInputStream fs = null;//参数"r"只读
fs = new BufferedInputStream(new FileInputStream(src));
//3.操作
byte[] b = new byte[1024]; //定义缓冲区
int len = 0;//实际读取长度
while (-1 != (len = fs.read(b))) {
fo.write(b, 0, len); //写入文件
fo.flush();
}
fs.close();
}
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
if (fo != null) {
fo.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//文件合并--法2--SequenceInputStream:将很多流组合成一个流的InputStream
public void merge2(String destPath){
/**
* @Description: SequenceInputStream(Enumeration<? extends InputStream> e)
* Enumeration:vector
* @Param:
* @return: void
*/
//1.创建源
File dest = new File(destPath);
//2.选择流
SequenceInputStream sis = null; //输入流
BufferedOutputStream fo = null; //输出流
//创建一个容器用于后面组合流
Vector<InputStream> vi = new Vector<>();
try {
for (int i = 0; i < blockPath.size(); ++i){
vi.add(new BufferedInputStream(new FileInputStream(new File(this.blockPath.get(i)))));
}
sis = new SequenceInputStream(vi.elements()); //SequenceInputStream组合流;vi.elements()返回此向量的枚举
fo = new BufferedOutputStream(new FileOutputStream(dest,true));
//3.操作
byte[] b = new byte[1024]; //定义缓冲区
int len = 0;//实际读取长度
while (-1 != (len = sis.read(b))) {
fo.write(b, 0, len); //写入文件
fo.flush();
}
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
if (fo != null) {
fo.close();
}
if (sis != null) {
sis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args){
String fileSrc = "/Users/braincao/git/1.txt"; //要分割的文件
String destPath = "/Users/braincao/git"; //分割后文件存放目录
String destMergePath = "/Users/braincao/git/test.txt"; //合并后文件的路径
SplitFileDemo file = new SplitFileDemo(fileSrc, destPath, 20);
file.split(); //文件分割
// file.mergeFile(destMergePath); //文件合并--法1
file.merge2(destMergePath); //文件合并--法2
}
}
File类的一个例子
获取git目录下后缀名为.txt的文件
public static void test1(){
File file = new File("/Users/braincao/git");
FilenameFilter filter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".txt"); //文件名的后缀要以.txt
}
};
String[] ff = file.list(filter);
for(String f: ff){
System.out.println(f);
}
}
日期Date、Calendar相关Demo
打印指定日期的月历:
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;
/**
* @Description: 键盘输入一个日期,打印该日期所在月份的月历
*/
public class TestDemo{
public static void main(String[] args) throws ParseException {
//1.获取输入字符串的日期
System.out.println("请输入想要查看的日期:(2018-11-09)");
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
Date d = java.sql.Date.valueOf(s);
Calendar cal = Calendar.getInstance();
cal.setTime(d);
int thisDay = cal.get(Calendar.DAY_OF_MONTH); //指定的日期
int days_of_month = cal.getActualMaximum(Calendar.DAY_OF_MONTH); //这个月有多少天。getActualMaximum-->返回指定Calendar日历字段可能拥有的最大值。
cal.set(Calendar.DAY_OF_MONTH, 1);
int week_of_firstDay_of_month = cal.get(Calendar.DAY_OF_WEEK); //这个月1号是周几
//2.打印指定日期的月份
System.out.println("日\t一\t二\t三\t四\t五\t六");//1周日 2周一 3周二 4周三 5周四 6周六 7周日
//2.1 打印1号之前的空格
String suffixHead = "";
for(int i=1; i<=week_of_firstDay_of_month-1; ++i){
suffixHead = suffixHead+"\t";
}
System.out.print(suffixHead);
int cnt = week_of_firstDay_of_month; //打印月历时换行的计数器
//2.2 打印本月月份,并将指定的当天日期后加"*"
for(int cntDay=1; cntDay<=days_of_month; ++cntDay){
if(cntDay==thisDay){
System.out.print(cntDay + "*\t");
}
else{
System.out.print(cntDay + "\t");
}
//判断是否换行
if(cnt%7 == 0){
System.out.println();
cnt = 1;
}
else{
cnt++;
}
}
}
}
out:
请输入想要查看的日期:(2018-11-09)
2018-10-09
日 一 二 三 四 五 六
1 2 3 4 5 6
7 8 9* 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
枚举Demo
什么情况用枚举:值比较少且固定时
import java.text.ParseException;
/**
* @Description: 枚举使用Demo
*/
enum Gendar{ //枚举
男, 女
}
class Person{
private String name;
private int age;
private Gendar sex; //使用枚举
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
public Person(String name, int age, Gendar sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public Person() {
}
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 Gendar getSex() {
return sex;
}
public void setSex(Gendar sex) {
this.sex = sex;
}
}
public class TestDemo{
public static void main(String[] args) throws ParseException {
Person p = new Person();
p.setName("张三");
p.setAge(25);
p.setSex(Gendar.男); //用枚举进行设置。好处:如果是String类型的sex,会遇到乱七八糟的String,这样给判断String带来很多麻烦,用枚举更好
System.out.println(p.toString());
//枚举与switch结合使用
Gendar sex = Gendar.女;
switch (sex){
case 男:
System.out.println("这是男孩");
break;
case 女:
System.out.println("这是女孩");
break;
}
}
}
Math.random()与Random r = new Random(long seed)
public static void main(String[] args){
System.out.println(Math.random()*10);
System.out.println("-------------");
Random r = new Random(10); //new Random(long seed)seed是生成随机数的种子,seed不变生成的随机数也不变,seed变了随机数也就变了
for(int i=0; i<5; ++i){//重复运行发现生成的随机数都相同,伪随机数
System.out.println(r.nextInt());
}
System.out.println("-------------");
Random r1 = new Random(System.currentTimeMillis()); //new Random(long seed)seed是生成随机数的种子,seed不变生成的随机数也不变,seed变了随机数也就变了
for(int i=0; i<5; ++i){//重复运行发现生成的随机数都不同,因为种子变了
System.out.println(r1.nextInt());
}
}
out:
1.7647342360229157
-------------
-1157793070
1913984760
1107254586
1773446580
254270492
-------------
958951514
-1748165986
967614401
9816424
-782039092
管道流
PipedInputStream和PipedOutputStream:输入输出可以直接进行连接,通过结合线程使用。
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/**
* @Description: 管道流结合多线程使用
*/
public class TestDemo{
public static void main(String[] args) throws IOException {
PipedInputStream input = new PipedInputStream();
PipedOutputStream output = new PipedOutputStream();
input.connect(output);
new Thread(new Input(input)).start(); //Input是一个线程
new Thread(new Output(output)).start(); //Output是一个线程
}
}
class Input implements Runnable{
private PipedInputStream in;
public 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 (IOException e){
e.printStackTrace();
}
}
}
class Output implements Runnable{
private PipedOutputStream out;
public Output(PipedOutputStream out){
this.out = out;
}
public void run(){
try{
out.write( "hi,管道来了!".getBytes());
out.flush();
out.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
//out: s=hi,管道来了!
欢迎转载,欢迎错误指正与技术交流,欢迎交友谈心
文章标题:java IO
文章字数:7.6k
本文作者:Brain Cao
发布时间:2018-12-16, 15:54:20
最后更新:2020-03-15, 16:11:45
原始链接:https://braincao.cn/2018/12/16/java-io/版权声明:本文为博主原创文章,遵循 BY-NC-SA 4.0 版权协议,转载请保留原文链接与作者。