深入理解Java中的流---结合Hadoop进行详解
Posted 安静的技术控
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解Java中的流---结合Hadoop进行详解相关的知识,希望对你有一定的参考价值。
在JavaSe的基础课程当中,可以说流是一个非常重要的概念,并且在Hadoop中得到了广泛的应用,本篇博客将围绕流进行深入的详解。
(一)JavaSe中流的相关概念
1、流的定义
①在Java当中,若一个类专门用于数据传输,则这个类称为流
②流就是程序和设备之间嫁接以来的一根用于数据传输的管道,这个设备可以是本地硬盘,可以是内存条,也可以是网络所关联的另外一台计算机等等,其中不同管道上有不同的按钮,按下不同的按钮相当于调用不同的方法,这根带按钮的用于数据传输的管道就是流,即流就是一根管道
③流一定是类,但类不一定是流
2、流的分类
按照数据流的方向不同分为输入流与输出流、按照处理数据单位的不同分为字节流与字符流、按照功能的不同分为原始流与包裹流。
输入流与输出流:所谓输入流就是通过输入管道从指定的设备当中读取数据,例如键盘。所谓输出流就是通过输出管道向指定的设备当中写入数据,例如显示器。
字节流与字符流:字节流处理数据的单位是一个字节,字符流处理数据的单位是一个字符,在Java当中一个字符相当于两个字节。
原始流:可以从一个特定的设备即数据 源中读写数据的流,就像是一条单一的管道接到水龙头上开始放水。
包裹流:所谓包裹流就是由于原始流的功能太简单了,对原始流进行一定的加工处理—-在原始流的基础上套一个功能比较强大的管子,这个管子称为包裹流。包裹流类似于在一条已经存在的管子套上另外一根管子。
原始流与包裹流的关键区别在于能不能直接连接到设备。
3、四大基本抽象流
所谓四大基本抽象流就是四大基本抽象类,四大基本抽象流包括字节流和字符流,其中字节流包括InputStream和OutPutstream,字符流包括Reader和Writer,并且凡是以Stream结尾的都是字节流。
字节流与字符流的方法一模一样,仅仅是处理数据的单位不一样;InputStream是所有字节输入流的父类、OutputStream是所有字节输出流的父类;Reader是所有字符输入流的父类,Writer是所有字符输出流的父类。
4、IO包中常用的流
文件流(原始流):
FileInputStream FileReader
FileOutputStream FileWriter
输出流(原始流):
PrintStream
缓冲流(包裹流):
BufferedInputStream BufferedReader
BufferedOutputStream BufferedWriter
转换流(包裹流):
InputStreamReader
OutputStreamWriter
数据流(包裹流):
DatainputStream
DataOutputStream
5、文件流、输出流、缓冲流、转换流、数据流的相关作用
文件流:Java中的文件流可以将一个文件的内容按字节或字符为单位来进行读写、复制
输出流:PrintStream在OutputStream基础之上提供了增强的功能,可以将基本类型数据格化后的字符串进行输出
缓冲流:缓冲流就是带有缓冲区的输入输出流,带缓冲区的流比不带缓冲区的流运行速度要快,因为此时此刻不是读一个写一个,而是读取完之后先放到缓冲区里面,在一次性写到指定的设备当中
转换流:InputStreamReader的作用是将输入字节流转换成字符流
OutputStreamWriter的作用是将输出字节流转换成字符流
数据流:Java中的数据流能够以一种与机器无关的方式,直接从底层字节输入流当中读取基本类型数据或者直接将基本类型数据写到字节输出流当中,即数据流可以将基本类型数据的二进制直接读入或写出
6、简述字节流与字符流的区别
1>字节流可以处理所有格式的文件,但是带有汉字的文本通过字节流输出到显示器上时会出现乱码的现象,但是若要完成的是文本文件的复制则不会出现乱码的现象—即字节流可以完成文本文件的拷贝
但是Hadoop中的IOUtils工具类解决了字节流的这个缺陷
2>字符流只能处理文本格式的文件,不能处理非文本格式的文件,因为非文本格式的文件本身就不是由一个一个字符组成的,因此若要当做一个一个字符来解读肯定会出错
3>在实际项目当中字节流是广泛使用的
(二)JavaSe中流的具体应用—-结合Hadoop中的Api(IOUtils)
IOUtils是Hadoop自己提供的工具类,在编程的过程中用的非常方便———import org.apache.hadoop.io.IOUtils,下面将结合具体的实例进行说明。
实际开发过程中提倡2点:
1>尽量用字节流处理问题
2>尽量用Hadoop中的org.apache.hadoop.io.IOUtils工具类解决问题,因为简单
实例1:读取一个文件的内容,并将其输出到显示器上
方法①
package JavaSe;
import java.io.BufferedReader;
import java.io.FileReader;
public class App1
{
public static void main(String[] args) throws Exception
{
BufferedReader fr = new BufferedReader(new FileReader("C:\\\\file.txt"));
int i = fr.read();
while(-1!=i)//-1表示读取到了文件的末尾
{
System.out.print((char)i);
i = fr.read();
}
}
}
//运行结果:
/*
Sometimes your plans don’t work out because God has better ones.
毅力和耐性在某种程度上将决定一个人会成为什么样的人。
*/
方法②
package JavaSe;
import java.io.BufferedReader;
import java.io.FileReader;
public class App1
{
public static void main(String[] args) throws Exception
{
BufferedReader fr = new BufferedReader(new FileReader("C:\\\\file.txt"));
char[] buf = new char[1024];
int len = fr.read(buf);//从fr所关联的文件当中读取数据并存放在数组buf中
System.out.println(new String(buf,0,len));
}
}
//运行结果:
/*
Sometimes your plans don’t work out because God has better ones.
毅力和耐性在某种程度上将决定一个人会成为什么样的人。
*/
方法③利用Hadoop自带的工具类:IOUtils(解决了字节流将汉字文本输出到显示器上时出现乱码的缺陷),并且相比于JavaSe中IO的方法更简单
package JavaSe;
import java.io.FileInputStream;
import org.apache.hadoop.io.IOUtils;
public class App1
{
public static void main(String[] args) throws Exception
{
FileInputStream fr = new FileInputStream("C:\\\\file.txt");
IOUtils.copyBytes(fr,System.out,1024,true);
}
}
//运行结果:
/*
Sometimes your plans don’t work out because God has better ones.
毅力和耐性在某种程度上将决定一个人会成为什么样的人。
*/
实例2:编程实现文件的复制—将C盘下的file.txt文本文件复制到D盘下的file2.txt文本文件中
方法①
package JavaSe;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class App2
{
public static void main(String[] args) throws Exception
{
BufferedInputStream fr = new BufferedInputStream(new FileInputStream("C:\\\\file.txt"));
BufferedOutputStream fw = new BufferedOutputStream(new FileOutputStream("D:\\\\file2.txt"));
int i = fr.read();
while(-1!=i)
{
fw.write(i);
i = fr.read();
}
fw.flush();
fr.close();
fw.close();
}
}
方法②
package JavaSe;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class App2
{
public static void main(String[] args) throws Exception
{
BufferedInputStream fr = new BufferedInputStream(new FileInputStream("C:\\\\file.txt"));
BufferedOutputStream fw = new BufferedOutputStream(new FileOutputStream("D:\\\\file2.txt"));
byte[] buf = new byte[1024];
int i = fr.read(buf);
fw.write(buf,0,i);
fw.flush();
fw.close();
fr.close();
}
}
方法③利用Hadoop自带的工具类:org.apache.hadoop.io.IOUtils,相比于JavaSe中IO的方法更简单
package JavaSe;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.PrintStream;
import org.apache.hadoop.io.IOUtils;
public class App2
{
public static void main(String[] args) throws Exception
{
BufferedInputStream fr = new BufferedInputStream(new FileInputStream("C:\\\\file.txt"));
System.setOut(new PrintStream("D:\\\\file2.txt"));//对于标准输出流进行重定向
IOUtils.copyBytes(fr,System.out,1024,true);
}
}
实例3:利用BufferReader中的readLine()方法和BufferedWriter中的writeLine()方法完成文本文件的复制—-项目中常做这个事情
package JavaSe;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
public class App3
{
public static void main(String[] args) throws Exception
{
BufferedReader fr = new BufferedReader(new FileReader("C:\\\\file.txt"));
BufferedWriter fw = new BufferedWriter(new FileWriter("D:\\\\file2.txt"));
String str = fr.readLine();
while(str!=null)
{
fw.write(str);
fw.newLine();
str = fr.readLine();
}
fw.flush();
fr.close();
fw.close();
}
}
实例4:编程实现将long基本类型数据写入byte数组,然后再从byte数组中把该数据读出来—-这是Socket编程中经常要完成的任务
方法①
package JavaSe;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.util.Scanner;
public class App4
{
public static void main(String[] args) throws Exception
{
Scanner scanner = new Scanner(System.in);
long i = scanner.nextLong();
ByteArrayOutputStream array = new ByteArrayOutputStream();//内核为字节数组
DataOutputStream fw = new DataOutputStream(array);
fw.writeLong(i);//将长整型变量i写到字节数组中
byte[] byteArray = array.toByteArray();//拷贝array内核字节数组的内容
ByteArrayInputStream bytearray = new ByteArrayInputStream(byteArray);
DataInputStream fr = new DataInputStream(bytearray);
long j = fr.readLong();
System.out.println(j);
}
}
//运行结果:
/*
65
65
* */
方法②
package JavaSe;
import java.util.Scanner;
public class App4
{
public static void main(String[] args) throws Exception
{
Scanner scanner = new Scanner(System.in);
long i = scanner.nextLong();
String str = i +"";
byte[] bytes = str.getBytes();//将长整型变量i间接存到数组中
System.out.println(new String(bytes));
}
}
//运行结果:
/*
65
65
* */
注:本例子不适合用Hadoop自带的工具类:org.apache.hadoop.io.IOUtils进行解决
实例5:利用数据流完成一个基本类型数据序列化与反序列化的实例
package JavaSe;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Scanner;
public class App5
{
public static void main(String[] args) throws Exception
{
Scanner scanner = new Scanner(System.in);
int i = scanner.nextInt();
int j = scanner.nextInt();
DataOutputStream fw = new DataOutputStream(new FileOutputStream("C:\\\\file2.txt"));
fw.writeInt(i);
fw.writeInt(j);
DataInputStream fr = new DataInputStream(new FileInputStream("C:\\\\file2.txt"));
int i2 = fr.readInt();
int j2 = fr.readInt();
System.out.println(i);
System.out.println(j);
}
}
//运行结果:
/*
65
56
65
56
* */
序列化与反序列的注意事项:
1>所谓序列化就是将对象以二进制形式写到字节输出流当中,所谓反序列化就是将对象从字节输入流当中读取出来
2>序列化与反序列化的顺序要保持相同:哪个数据先写进流管道里,哪个数据就先从流管道里读出来
3>Java中的数据流是将基本类型数据的二进制代码写到文本文件中,而Java中的输出流PrintStream是将基本类型数据的字符串写到文本文件中/font>
下面为示例结果:
当我们将上面程序中的file2.txt文件打开之后结果如下:
其中:
00 00 00 41为65的16进制,00 00 00 38为56的16进制
实例5:编程实现将键盘输入的字符组成字符串直接赋给String对象
方法①
package JavaSe;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class App5
{
public static void main(String[] args) throws Exception
{
BufferedReader fr = new BufferedReader(new InputStreamReader(System.in));//将键盘输入的字节流转化为字符流
String str = fr.readLine();
System.out.println(str);
}
}
//运行结果:
/*
数据分析玩家shujufenxiwanjia
数据分析玩家shujufenxiwanjia
*/
方法②
package JavaSe;
import java.util.Scanner;
public class App5
{
public static void main(String[] args) throws Exception
{
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
System.out.println(str);
}
}
//运行结果:
/*
数据分析玩家shujufenxiwanjia
数据分析玩家shujufenxiwanjia
*/
实例6:标准输入输出的重定向:编程实现将键盘输入的数据输入file1.txt文件中,如果输入有误,则将出错信息输出到B文件中
所用知识点:
1>相关api如下图所示:
2>Java异常中的e.printStackTrace()方法默认是将出错信息输出到System.err所关联的设备中
package JavaSe;
import java.io.PrintStream;
import java.util.Scanner;
public class App6
{
public static void main(String[] args) throws Exception
{
System.setOut(new PrintStream("C:\\\\file1.txt"));//重定向输出
System.setErr(new PrintStream("C:\\\\file2.txt"));//重定向错误输出
while(true)
{
Scanner scanner = new Scanner(System.in);
try
{
int i = scanner.nextInt();
System.out.println(i);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
运行完毕后:
file1.txt文本文件中的内容为:
23
56
file2.txt文本文件中的内容为:
java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:864)
at java.util.Scanner.next(Scanner.java:1485)
at java.util.Scanner.nextInt(Scanner.java:2117)
at java.util.Scanner.nextInt(Scanner.java:2076)
at JavaSe.App1.main(App1.java:19)
针对JavaSe基础编程当中流的用法就写到这里,如有问题,欢迎留言指正!
以上是关于深入理解Java中的流---结合Hadoop进行详解的主要内容,如果未能解决你的问题,请参考以下文章