黑马程序员-java-I/O

Netty4学习笔记(4)-- ByteBuf和设计模式 介绍Netty4 ByteBuf 阅读详情

---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------


      java语言的输入输出功能是十分强大而且灵活的,它涉及的领域很广泛:标准输入输出,文件的操作,网络上的数据流,字符串流,对象流等。


流的概念:

当程序需要读取数据时,就会开启一个通向数据源的流,这个数据可以是文件,内存,或是网络连接。类似地,当需要写入数据的时候,就会开启一个通向目的的流,这时候,就可以想象数据好像在这其中'流动'一样。

javaI/O流:

1,I/O流用来处理设备之间的数据传输。
1,I/O流对数据的操作时通过流的方式。
2,java用于操作流的对象都在IO包中.
3,流操作按数据分为两种: 字节流和字符流.
4,流按流向分为: 输入流,输出流。
其中字节流的两个基类为:InputStream,OutputStream。字符流的两个基类为:Reader,Writer。
注:有这四个类派生出的子类名称都是以其父类名作为子类的后缀。
如:InputStream的子类: FileInputStream
如:Reade的子类: FileReader

java I/O框架图:



文件字符输出流FileWriter:

用FileWriter将数据写入到指定文件中的例子:

<span style="font-family:KaiTi_GB2312;font-size:18px;">pubic class test
{
	public static void main(String[] args) throws Exception
	{
		//FileWriter在构造函数中知指定目标文件的时候,如果在指定目录下有同名文件,则将其覆盖。
		FileWriter fileWriter = new FileWriter("g:\\java\\test.txt");

		//调用write方法,将字符串写入到该流的缓冲区
		fileWriter.write("abc");
		
		// 刷新该缓冲区,将缓冲区中的字符数据写入到目标文件中。
		fileWriter.flush();		
	
		//关闭流
		fileWriter.close();
		
	}	
}</span>

I/O异常处理:上例中的代码是很不严谨的,首先,指定的目标文件的存放位置可能不存在,还有就是无论如何,都必须关闭流,因此,应该将关闭流这个操作放在finally块中。
改写如下:

<span style="font-family:KaiTi_GB2312;font-size:18px;">public class  test
{
	public static void main(String[] args) throws Exception
	{
		FileWriter fileWriter  =  null;
		
		try 
		{
			fileWriter = new FileWriter("g:\\java\\test.txt");
			
			fileWriter.write("abc");
		} 
		catch (Exception e)
		{
			System.out.println(e.toString());
		}
		finally
		{
			try 
			{
				if(fileWriter != null) //判断fileWriter是否为null
				{
					fileWriter.close();
				}
			}
			catch (Exception e2) 
			{
				System.out.println(e2.toString());
			}
		}
		
	}
}</span>

文件的续写:在FileWriter的构造函数中传递一个true,代表不覆盖已有的文件,即不重新对该文件进行数据写入,而是从文件的末尾开始写入数据。
例如:fileWriter = new FileWriter("g:\\java\\test.txt",true);


文件字符输入FileReader:
FileReader类中的read()读取单个字符,返回字符的整数值,如果已经导到输入流尾部,则返回-1,它是输入流中的最基本的读取函数。
FileReader类中的read(char[] cbuf)将字符读入cbuf数组,返回读取到的字节书,如果已经导到输入流尾部,则返回-1。
例子:

<span style="font-family:KaiTi_GB2312;font-size:18px;">public class test
{
	public static void main(String[] args) throws Exception
	{
		FileReader fileReader  = null;
		int len = 0;
		char[] buf = null;
		try 
		{
			fileReader = new FileReader("g:\\java\\demo.txt");
			
			buf = new char[10];  //存放读取字符的数组,一次最多读取十个字符
			
			while((len = fileReader.read(buf)) != -1) //如果还没有读到末尾
			{
				System.out.print(String.valueOf(buf, 0, len)); //打印读取到的字符
			}
						
		} 
		catch (Exception e)
		{
			System.out.println(e.toString());
		}
		finally
		{
			try 
			{
				if(fileReader != null)
				{
					fileReader.close();
				}
			}
			catch (Exception e2) 
			{
				System.out.println(e2.toString());
			}
		}
		
	}
}</span>
因为字符输入输出流在数据上的基本操作实际上都是单个字符,这样效率是很低的,于是java提供了缓冲区技术。
缓冲字符输入流: BufferedReader
缓冲字符输出流: BufferedWriter
建立缓冲区之前,必须要先有相应的流对象。只要在缓冲字符类的构造函数中传入相应的流对象。而且关闭缓冲区实际上关闭的就是相应的流。
BufferedReader类中的readLine()读取的是文本中的一行数据,其中不包括换行符。
BufferedWriter类中的write(String line)将一行字符串写入流中,newLine()写入换行符(跨平台),flush()刷新缓冲区。
例子(复制文本文件):
<span style="font-family:KaiTi_GB2312;font-size:18px;">public class test
{
	public static void main(String[] args)
	{
		BufferedReader bufferedReader = null;	
		BufferedWriter bufferedWriter = null;
		try
		{       //创建缓冲字符输入流和输出流
			bufferedReader = new BufferedReader(new FileReader("g:\\java\\test.java"));
			bufferedWriter = new BufferedWriter(new FileWriter("g:\\java\\copytest.java");
			
			String line = null;
			while((line = bufferedReader.readLine()) != null)
			{
				bufferedWriter.write(line); //将读取到的一行字符串(不含换行符)写到缓冲输出流中
				bufferedWriter.newLine();  //写入一个换行符
				bufferedWriter.flush();    //刷新缓冲区
			}
		}
		catch (Exception e)
		{
			System.out.println(e.toString());
		}
		finally
		{
			try 
			{
				if(bufferedReader != null)
					bufferedReader.close();
			}
			catch (Exception e2) 
			{
				System.err.println(e2.toString());
			}
		}				
	}
}</span>

字符缓冲区中实际上是封装了一个字符数组,根据这个原理,自定义一个缓冲字符输入流MyBufferedReader,它继承Reader,并覆盖close()和read(char[] cbuf,int offset,int len)两个抽象函数。

<span style="font-family:KaiTi_GB2312;font-size:18px;">class MyBufferedReader extends Reader
{
	private Reader reader;
	
	public MyBufferedReader(Reader reader)
	{
		this.reader = reader;
	}
	

	//自定义的读取一行数据的函数,返回的字符串不包括换行符。
	public String myReadeLine() throws IOException
	{
		StringBuilder sb = new StringBuilder();
		
		int ch = 0;
		
		
		while((ch = reader.read()) != -1)
		{
			if(ch == '\r')
				continue;
			else if(ch == '\n')
				return sb.toString();
			else sb.append((char)ch);
		}
		//如果长度不为0,返回最后一行字符串。
		if(sb.length() != 0)
			return sb.toString();
		return null;
	}
	
	public int read(char[] buf,int off, int len) throws IOException
	{
		return read(buf, off, len);
	}
	
	public void close() throws IOException
	{
		reader.close();
	}
}</span>


装饰设计模式:
上面自定义的输入缓冲流用到了装饰设计模式,当希望给一个对象增加一些新的功能而且是动态的时候,必须要求装饰对象和被装饰对象都实现同一个接口或抽象类。
装饰和继承的区别:
装饰模式比继承更灵活,避免了继承所带来的代码臃肿问题,而且降低了类与类之间的耦合性。
装饰类以为增强已有对象的功能,具备的功能金额已有的是相同的,只不过提供了更强的功能。所以装饰类和被装饰类都属于同一个体系。
装饰类模式的应用场景:
1,需要扩展一个类的功能。
2,动态地为一个对象增加功能,而且还能动态撤销(这源于装饰类和被装饰类都继承了同一接口)。
(继承做不到这一点,继承的功能时静态的,不能动态地增删)
装饰设计模式的弊端: 产生过多相似的对象,不易排错。


字节流:
FileInputStream:
1,int avalible()得到当前可读的输入字节数。
2,int read()读取单个字节的数据,如果当前已到文件末尾,则返回-1。
3,int read(byte[] buf)从输入源中读取buf.length个数据到buf字节数组中,返回实际成果读取到的字节数,若当前在文件末尾则返回-1.
FileOutputStream:
1,void flush()刷新输出缓冲区,即把缓冲区中的数据持久化到文件中,并清空缓冲区。
2,int write(int b想输出缓冲区写入b的低八位,b的高24位将被忽略。
3, void write(byte[] buf)将字节数组buf中的数据全部写入到文件输出流。
4,void write(byte[] buf,int offset,int len)写入字节数组中的指定位置和长度的连续字节。
用字节流复制文件的例子:
<span style="font-family:KaiTi_GB2312;font-size:18px;">public class test
{
	public static void main(String[] args)
	{
		FileInputStream fileInputStream = null;
		FileOutputStream fileOutputStream  = null;
		byte[] buf = null;
		try 
		{
			fileInputStream = new FileInputStream("g:\\java\\test.java");
			fileOutputStream = new FileOutputStream("g:\\java\\copybyte.java");
			buf = new byte[1024]; //存放读取字节的数组,一次最多读1024个字节
			int len = 0;
			while((len = fileInputStream.read(buf)) != -1) 
			{
				fileOutputStream.write(buf, 0, len); //将数组中的字节写入字节输出流 
				fileOutputStream.flush();            //刷新字节输出流
			}
		} 
		catch (Exception e) 
		{
			e.toString();
		}
		finally
		{
			try 
			{
				if(fileInputStream != null)
					fileInputStream.close();
				
				if(fileOutputStream != null)
					fileOutputStream.close();
			} 
			catch (Exception e2) 
			{
				
			}
		}
	}
}</span>

java同样为字节流提供了缓冲区技术:
缓冲字节输入流 BufferedInputStream
int read(byte[] buf)从输入源中读取buf.length个数据到buf字节数组中,返回实际成果读取到的字节数,若当前在文件末尾则返回-1.
缓冲字节输出流 BufferedOutputStream
void write(byte[] buf,int offset,int len)写入字节数组中的指定位置和长度的连续字节。

<span style="font-family:KaiTi_GB2312;font-size:18px;">public class test
{
	public static void main(String[] args)
	{
		FileInputStream fileInputStream = null;
		FileOutputStream fileOutputStream  = null;
		BufferedInputStream bufferedInputStream = null;
		BufferedOutputStream bufferedOutputStream = null;
		byte[] buf = null;
		try 
		{
			fileInputStream = new FileInputStream("g:\\java\\test.java");
			fileOutputStream = new FileOutputStream("g:\\java\\copybyte.java");
			bufferedInputStream = new BufferedInputStream(fileInputStream);//缓冲字节输入流
			bufferedOutputStream = new BufferedOutputStream(fileOutputStream); //缓冲字节输出流
			buf = new byte[1024];
			int len = 0;
			while((len = bufferedInputStream.read(buf)) != -1)
			{
				bufferedOutputStream.write(buf, 0, len); //将读取到的字节写到缓冲区中
				bufferedOutputStream.flush();  //刷新缓冲区
			}
		} 
		catch (Exception e) 
		{
			e.toString();
		}
		finally
		{
			try 
			{
				if(bufferedInputStream != null)
					bufferedInputStream.close();
				
				if(bufferedOutputStream != null)
					bufferedOutputStream.close();
			} 
			catch (Exception e2) 
			{
				
			}
		}
	}
}</span>

同样在字节缓冲输入流中实际上是封装了一个字节数组,利用装饰设计模式,我们也设计一个自定义的缓冲字节输入流MyBufferedInputStream,继承InputStream,覆盖close方法和read方法。

<span style="font-family:KaiTi_GB2312;font-size:18px;">class MyBufferedInputStream extends InputStream
{
	private InputStream in;
	private byte[] buf = new byte[1024];
	private int pos = 0,count =0;
	
	MyBufferedInputStream(InputStream in)
	{
		this.in = in;
	}
	
	public int read() throws IOException
	{
		if(count == 0)
		{       
                       //将读取的字节放入buf数组中,并将读取到的字节个数返回给count
			 count = in.read(buf); 
			if(count < 0) //如果count为-1,说明已经到末尾,直接return -1结束读取
			return -1;
			pos = 0; //否则取第一个字节返回,并准备读取下一个字节
			byte b = buf[pos];
			count--;
			pos++;
			return b&0xff; //为避免类型提升时出现前面都补1导致出现返回值为-1的情况,与上0xff。
		}
		else
		{
			byte b = buf[pos]; //读取pos位置处的一个字节
			count--; //剩余字节数减一
			pos++; 
			return b&0xff; //返回此次读取到的字节
		}
	}
	public void close()throws IOException
	{
		in.close();
	}
}</span>


转换流:
为了便于对数据的操作,有时需要将字节流转换成缓冲字符流对象。
读取转换流:InputStreamReader。
例如将标准输入流对象转换成缓冲字符输入流对象:BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
写入转换流:OutputStream。
例如将标砖输出流对象转换成缓冲字符输出流对象:BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
流操作规律:
1,明确源和目的:
    源: 输入流: InputStream , Reader
  目的:输出流: OutputStream, Writer
2,操作的数据是否是纯文本。
 是: 字符流
 否: 字节流
3,当体系明确后,再明确具体要使用哪个具体的对象。
   通过设备来进行区分:
 源设备:内存,硬盘,键盘
 目的设备: 内存,硬盘,控制台


java文件操作:
File类的常见方法:
1,boolean createNewFile()  创建文件,在指定位置创建文件,如果该文件已经存在,则不创建,放回。
2,boolean delete()   删除文件或目录。
3,String getAbsolutePath()  返回此抽象路径名的绝对路径名字符串。
4,String getCanonicalPath()    返回此抽象路径名的规范路径名字符串。
5,String getName()    返回由此抽象路径名表示的文件或目录的名称。
6,String getParent()  返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。
7,boolean isDirectory()  测试此抽象路径名表示的文件是否是一个目录。
8,boolean isFile()      测试此抽象路径名表示的文件是否是一个标准文件。
9,boolean exists()    测试此抽象路径名表示的文件或目录是否存在。
10,long length()    返回由此抽象路径名表示的文件的长度   
 
11,File[] listFiles()   返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
12,boolean mkdir()   创建此抽象路径名指定的目录。
13,boolean mkdirs()   创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。
 
14,static String separator     与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。
下面以复制c盘中的一个文件夹到d盘中为例,说明各函数的用法:
<span style="font-family:KaiTi_GB2312;font-size:18px;">public class CopyFile 
{

	public static void main(String[] args) throws Exception
	{
		String source = "c:\\test";
		String dest = "d:\\trytest";
		write2Dir(source,dest);
	}
	
	
	//将SourceFile标准文件对象中的数据复制到DestFile标准文件对象中
	public static void write2file(File SourceFile,File DestFile)
	{
		BufferedInputStream inputStream = null;
		BufferedOutputStream outputStream = null;
		try 
		{
			inputStream = new BufferedInputStream(new FileInputStream(SourceFile));
			outputStream = new BufferedOutputStream(new FileOutputStream(DestFile));
			
			byte[] buf = new byte[1024];
			int len = 0;
			while((len = inputStream.read(buf)) != -1)
			{
				outputStream.write(buf,0,len);
			}
			outputStream.flush();
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		finally
		{
			try 
			{
				if(inputStream != null)
					inputStream.close();
				if(outputStream!=null)
					outputStream.close();
			} 
			catch (Exception e2) 
			{
				e2.printStackTrace();
			}
		}
	}
	
	//利用递归,将指定路径名中的一个文件夹复制到目标路劲所对应的位置。
	public static void write2Dir(String sourceDir,String desDir) throws IOException
	{
		//在目标路劲位置创建一个同名文件夹
		(new File(desDir)).mkdirs();
		//获得源路径名指定的文件夹中所有的File对象
		File[] files = (new File(sourceDir)).listFiles();
		for(int i=0; i<files.length; i++)
		{
			//如果是一个标准文件
			if(files[i].isFile())
			{
				File SourceFile = files[i]; 
				//根据目标路劲名创建一个文件对象。
				File DestFile = new File(new File(desDir).getCanonicalPath()+(String)File.separator+files[i].getName());
				
				//复制标准文件
				write2file(SourceFile,DestFile);
			}
			//如果是一个目录
			if(files[i].isDirectory())
			{
				//获得下以层源目录的路径名
				String source = sourceDir + File.separator  +  files[i].getName();
				//同时获得目标目录的路径名
				String dest = desDir + File.separator  +  files[i].getName();
				//递归
				write2Dir(source, dest);
			}
		}
	}
}</span>


合并流SequenceInputStream:
1,SequenceInputStream(Enumeration<? extends InputStream> e) 通过记住参数来初始化新创建的 SequenceInputStream,
 该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
2,SequenceInputStream(InputStream s1, InputStream s2)通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),
 以提供从此 SequenceInputStream 读取的字节。
3, int read(byte[] buf) 将最数据字节从此输入流读入 byte 数组。
例子(将三个文件合并成一个文件)
<span style="font-family:KaiTi_GB2312;font-size:18px;">public class test
{
	public static void main(String[] args) throws Exception
	{
		Vector<FileInputStream> vector = new Vector<FileInputStream>();		
		vector.add(new FileInputStream("g:\\java\\1.txt"));
		vector.add(new FileInputStream("g:\\java\\2.txt"));
		vector.add(new FileInputStream("g:\\java\\3.txt"));
		
		Enumeration<FileInputStream> enumeration = vector.elements(); //得到InputStream 对象的 Enumeration 型参数。
		
		FileOutputStream fos = new FileOutputStream("g:\\java\\4.txt");//文件输出流
		SequenceInputStream sequenceInputStream = new SequenceInputStream(enumeration);	
		byte[] buf = new byte[1024];	
		int len = 0;
		
		while((len = sequenceInputStream.read(buf)) != -1)
		{
			fos.write(buf, 0, len); //将合并文件流写入到相应的字符文件输出流
			fos.flush();            //刷新字符文件输出流
		}  
		
		fos.close();
		sequenceInputStream.close();
	}
}</span>

切割文件(将制定文件切割成一个个大小为1KB的文件):

<span style="font-family:KaiTi_GB2312;font-size:18px;">public class test
{
	public static void main(String[] args) throws Exception
	{
		FileInputStream fis = new FileInputStream("g:\\java\\test.java");
		FileOutputStream fos = null;
		byte[] buf = new byte[1024];
		int len = 0;
		int count = 1;
		while((len = fis.read(buf)) != -1)
		{
			String string =  "g:\\java\\test"+(count++)+".java"; //要写入的文件名称
			fos = new FileOutputStream(string);      //根据文件名创建一个文件
			fos.write(buf,0,len);        //将1KB数据写入该文件
			fos.close();                 //关闭刚创建的字符文件输出流
		}
		
		fis.close();
	}
}</span>

Properties:
Properties是Hashtable的子类。也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串。
是集合中和IO相结合的集合容器。
Properties中的常用方法:
1,String getProperty(String key)   用指定的键在此属性列表中搜索属性。  
2,void load(InputStream inStream)     从输入流中读取属性列表(键和元素对)。
3,Object setProperty(String key, String value) 调用 Hashtable 的方法 put。
4,void list(PrintStream out)    将属性列表输出到指定的输出流。
 
5,Set<String> stringPropertyNames()   返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。
 
使用Properties的例子:

<span style="font-family:KaiTi_GB2312;font-size:18px;">public class test
{
 public static void main(String[] args) throws Exception
 {
  Properties pro = new Properties();
  InputStream in = new FileInputStream("g:\\java\\config.properties");
  pro.load(in);
  pro.list(System.out);
  pro.setProperty("zhangsan", "11");
  System.out.println(pro.get("zhangsan"));
  pro.list(System.out);
 }
}</span>

对象的序列化:
原理: java提供的输入输出流ObjectOutputStream和ObjectInputStream可以直接把java对象作为可存储可传输的对象写入文件,并在网络传输。
对象的序列原理其实很简单:
1,通过输出流保存的对象都获得一个序列号
2,当要保存一个对象时,先检查该对象的序列号是否已经存在
3,如果以前保存了,则只要写入‘与已经保存的具有序列号的对象相同’的标记,否则,保存该对象
java对象序列化机制专门设计了一个没有任何定义方法的java.io.Serializable接口,当一个java对象实现该接口后,java就为其提供一个唯一的序列号。
在基于对象输入输出流进行对象的存取的时候,有两个细节需要考虑:
1,某个对象有不希望进行存储和传输的部分属性,即使它们都实现了java.io.Serializable接口。
2,有些没有实现java.io.Serializable接口的类型的属性,但是却希望基于对象输入和输出流对其进行存取。
java提供了解决上述两种情况的方法
1,对于不行进行传输的对象的部分属性,可以用‘transient’关键字对其进行标识
2,对于被‘transient’标识的属性,java对象序列化机制设计了两个私有方法(readObject(ObjectInputStream in) 和 writeObject(ObjectOutputStream out)),
 这两个方法不需要显示调用,序列化机制会自动调用。
例子:

<span style="font-family:KaiTi_GB2312;font-size:18px;">class Person implements Serializable
{
	private int age;
	transient private String name; //声明name属性不进行传输
	
	public Person(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	
	public int getAge() {
		return this.age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}
        //定义wirteObject和readObject方法,将name属性进行基于对象输入和输出流的存取
	private void writeObject(ObjectOutputStream out) throws IOException
	{
		out.defaultWriteObject();
		out.writeObject(this.name);
	}
	
	private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException
	{
		in.defaultReadObject();
		this.name = (String) in.readObject()+".................";
	}
}

public class TestSerilizable
{
	public static void main(String[] args) throws Exception
	{
		File personFile = new File("myperson");
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(personFile));
		Person p = new Person("zhangsan",11);
		oos.writeObject(p);  //将对象持久化到myperson文件
		oos.close();
		
		ObjectInputStream oin = new ObjectInputStream(new FileInputStream(personFile));
		Person p1 = (Person)oin.readObject(); //读取文件中的对象
		System.out.println("name = "+p1.getName()+"::::"+"age = "+p1.getAge()); //打印属性
		oin.close();
	}
}</span>
虽然name属性被transient关键字标识,但类中实现了readObject(ObjectInputStream)和writeObject(ObjectOutputStream out)两个函数,序列化机制会自动调用他们对name进行写和读的操作。

管道流:
管道输入流:PipedInputStream
构造函数PipedInputStream(PipedOutputStream src, int pipeSize)  创建一个 PipedInputStream,使其连接到管道输出流 src,并对管道缓冲区使用指定的管道大小。
管道输出流:pipedOInputStream
构造函数PipedOutputStream(PipedInputStream snk) 创建连接到指定管道输入流的管道输出流。
可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。不建
议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于毁坏状态。

<span style="font-family:KaiTi_GB2312;font-size:18px;">class Read implements Runnable
{
	private PipedInputStream inputStream;
	Read(PipedInputStream inputStream)
	{
		this.inputStream = inputStream;
	}
	
	public void run()
	{
		try 
		{
			byte[] buf = new byte[1024];
			int len = inputStream.read(buf); //读取管道中的数据到buf字节数组中,该读取函数时线程阻塞性的,当管道流中没有数据时,会一直等待,直到管道中有数据并将其取走
			String string = new String(buf,0,len);
			System.out.println(string); 
			inputStream.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException("read failed");
		}
	}
	
}

class Write implements Runnable
{
	private PipedOutputStream outputStream;
	Write(PipedOutputStream outputStream)
	{
		this.outputStream = outputStream;
	}
	
	public void run()
	{
		try 
		{
			outputStream.write("piped is coming!!".getBytes()); //将数据写入管道流中
			outputStream.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException("read failed");
		}
	}
	
}</span>


RandomAccessFile:
1,RandomAccessFile是不属于InputStream和OutputStream类系的,它是一个完全独立的类,多有的方法都没有用到InputStream和OutputStream类系中的功能,
2,RandomAccessFile是专门用来操作文件的I/O类,内部封装了一个数组,而且通过指针对数组的元素进行操作,因此它可以在文件里前后移动,通过getFilePointer获得该指针和seek设置文件指针。
3,RandomAccessFile实现了一个标记接口RandomAccess,该标记接口用来标识那些可以支持快速随机访问的类,
构造函数:
1,RandomAccessFile(File file, String mode) //指定操作文件
2,RandomAccessFile(String name, String mode) //指定文件的名称
如果构造函数要操作的文件不存在,则创建一个文件。如果存在,并不会覆盖已经存在的文件,这点跟其他的文件操作的输入输出类不一样。
mode: 
"r" 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。  
"rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。  
"rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。  
"rwd"   打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。 
如果模式为r,且文件不存在时,则会报异常,如果rw,操作文件不存在,则自动创建,否则也不对已经存在的文件进行覆盖。
一些方法的使用:
1,write(int val) 和 writeInt(int val):write(int val)只写入val中的低八位,而 writeInt(int val)按四个字节写入文件。
2,seek(long pos)和skipBytes(int n):seek(long pos)所操作的范围比skipBytes(int n)范围要广,而且skipBytes(int n)不支持往前指向跳过的字节,而seek能指向文件的任何地方所以一般使用seek。

可以直接操作基本数据类型的流:DataInputStream和DataOutputStream:
1,String readUTF(DataInput in)从流in中读取用 UTF-8 修改版格式编码的 Unicode 字符格式的字符串,然后以 String 形式返回此字符串。
2,void writeUTF(String str)以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。

当使用writeUTF将一个字符串写入文件中时,只能用相对应的readUTF将其读出!!!


----------------------ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com

【codex教程】Codex 注册和使用教程(2026最新版) Codex 是 OpenAI 推出的 AI 编程助手,可以帮助开发者阅读代码、修改代码、运行命令、生成测试、排查 bug、做代码审查,也可以在终端、IDE、Codex App 或网页端使用。根据 OpenAI 帮助中心,截至 2026 年 6 月,Codex 已包含在 Free、Go、Plus、Pro、Business、Edu 和 Enterprise 等 ChatGPT 方案中,但不同套餐的使用额度会有所不同。适合开发者在终端中使用。如果你想在命令行里使用 Codex,可以安装 Codex CLI。 阅读详情

相关推荐

【sap2000】部分模型通过.s2k文件合并模型generating a global model through partial models by .s2k text file

现在需要通过选项File → Import → SAP2000 .s2k Text File → Add to existing model(如果使用其中一个部分模型作为基础)或New model(如果使用新文件)添加部分模型,并使用以下导入选项。模型A(阶段1/5) Model A (Phase 1/5)模型B(阶段2/5) Model B (Phase 2/5)模型C(阶段3/5) Model C (Phase 3/5)模型E(阶段5/5) Model E (Phase 5/5)

hmywillstronger的博客 1748

【华为OD统一考试B卷 | 200分】代表团坐车( C++ Java JavaScript python)

众所周知,--i表示先执行自减运算,然后再使用自减后的i变量值进行其他的运算。i--表示先使用i的值进行运算,然后再对i变量进行自减。相信大家在看各种辅导书的时候,都是这样去死记硬背的,并没有深入探究为什么会这样。我们先横向比较下其他语言中的--i与i--:可以肯定的是,基本上大部分语言类型如C、C++、Python、JavaScript等等语言,其执行的逻辑顺序和我开头的描述是一模一样的,只是在实现的原理上略有不同。

m0_57042151的博客 2121

Rocky Linux 9 远程桌面配置全攻略:从零搭建XRDP服务(含防火墙设置)

本文提供了在Rocky Linux 9上从零开始配置XRDP远程桌面服务的完整指南。详细介绍了系统准备、XRDP服务安装、防火墙与SELinux安全设置、多用户性能优化以及多平台客户端连接实测。重点解决了使用Windows远程桌面协议(RDP)连接Rocky Linux时常见的配置难点与安全问题,帮助用户获得稳定高效的图形化远程访问体验。

vodka的博客 646

黑马程序员——JavaIO

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- 自学Java第十天笔记。本人是根据毕向东老师的JavaSE视频学习的。 JavaIO 一.IO流。 1.用于处理设备上数据。(IO流用来处理设备之间的数据传输) 用到IO流时,写代码要导包import java.io.*; 2.流也进行分类: 1)、流按

zhaofengshiwo的专栏 555

【同等学力】2025-数学✨

本文主要涵盖了谓词逻辑、集合论、图论和排列组合等多个数学领域的题目。在谓词逻辑部分,要求用全称量词和存在量词表达“没有两个人的指纹完全相同”。集合论部分涉及集合运算的证明,如证明(A-B)-C=(A-C)-(B-C)。图论部分包括计算给定10个点的联通图的边与面数。排列组合部分则要求计算从8个人中选6个并分为三组的不同方法。此外,还涉及偏序、长链、反链、二项式定理等相关内容,参考了多个优快云博客中的解题思路。

super_mochi1 676

Auto.js实现视频号点赞自动化

摘要:本文介绍了一个微信视频号自动化点赞的实现方案。通过定位点赞图标和数量容器,点击点赞按钮后检测点赞数变化,若发现取消点赞则自动补点。核心代码包括:1)获取点赞容器和图标;2)记录点赞前后数量;3)判断是否误取消并补点;4)循环执行点赞和滑动页面操作。该方案解决了滑动页面可能导致误取消点赞的问题,实现了自动化批量点赞功能。文章强调仅供学习参考,提醒勿滥用该技术。

分享前端工程化、AI 应用、Agent 开发与大模型实践! 2573

Java中i+=i-=i*=i的运行结果是什么?

i*(2-i) 要搞清楚运算的方法和顺序 i += x ; ( x为 i-=i*=i ) 即i = i + x i -= y ; ( y 为 i*=i) 即 x = i -y i*=i 即 i = ii 即 y = ii 所以有 i = i + i - ii 即 i = i(2-i);

诚 8472

把财务与管理会计装进一张表:读懂 S/4HANA 的 ACDOCA

别慌,这反而是设计所需。只是大量历史上为汇总、加速而建的索引与汇总表被淘汰或改造,很多被兼容视图 compatibility views 替代,通过视图去 ACDOCA 或 ACDOCT 取数,从而保证老代码还能 SELECT 到数据,但失去写权限。它把原来分散在多张表里的信息整合到一起,例如总账、固定资产、物料账、盈利能力分析 CO-PA、成本控制等维度,发布过的资料多次强调这一点。其二,查询必须带上高选择性的条件,尤其是 RLDNR、RBUKRS、GJAHR 这三个维度,能大幅降低列存扫描的代价。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 941

黑马程序员——Java I/O系统

流,file

332

关于112G和56G PAM4信号的有效回损(ERL)

本文探讨了回波损耗(RL)对高速数字通信系统性能的影响,重点分析了时域信道运行裕度(COM)与频域回波损耗指标的关联性。研究表明,传统频域回波损耗指标在预测系统性能时存在假阳性/假阴性问题,特别是对PAM-4信号系统影响更为显著。通过引入基于时域脉冲响应的有效回波损耗(ERL)指标,并结合判决反馈均衡器(DFE)的补偿效应,可更准确评估系统性能。实验表明,短封装器件虽然频域回波损耗较差,但在实际系统中表现更优。研究提出通过时域门控加权等方法优化ERL计算,为高速互连设计提供了更可靠的性能评估框架。

小孟同学的博客 290

DCNv4+YOLOv8:2024最新可变形卷积赋能目标检测,从原理到实战的科研级优化指南

从理解DCNv4“自适应变形卷积核”的核心思想,到亲手将其嵌入YOLOv8并验证在复杂场景的检测效果,再到基于此探索属于自己的科研与工程方向——这个过程能让你深刻理解目标检测中“特征自适应提取”的核心价值。现在就开始行动,相信你会在目标检测的“自适应特征提取”之路上,走出一条属于自己的技术路径。实验通常会证明:嵌入DCNv4后,YOLOv8在复杂场景下的检测精度提升3-5个百分点,尤其是小目标和遮挡目标的AP提升更为明显,而推理速度仅下降5%-10%(可通过模型量化进一步优化)。2024年最新推出的。

m0_64661770的博客 267

黑马程序员-java基础——I/O

---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ---------------------- 详细请查看:www.itheima.com

dsw00523的专栏 348

如何使用freesurfer对T1w结构像进行分区指标的提取?——皮层面积,灰质体积,平均厚度,厚度标准差,平均曲率、高斯曲率、曲率指数、折叠指数

如何使用freesurfer对T1w结构像进行分区指标的提取?——皮层面积,灰质体积,平均厚度,厚度标准差,平均曲率、高斯曲率、曲率指数、折叠指数

从事脑科学核磁共振方法学研究,在Nature communications等权威期刊发表研究论文,熟练掌握磁共振处理方法和统计学方法,欢迎大家和我交流。 3786

黑马程序员java I/O系统1

------- android培训、java培训、期待与您交流! ---------- 黑马程序员java I/O系统1 File类的对象,表示了磁盘上的文件或目录,提供了与平台无关的方法来对磁盘上的文件或目录操作。File类描述了文件本身的属性,用来获取或处理磁盘文件相关的信息,例如权限,时间,日期和目录路径。File类还可以浏览子目录层次结构。目录管理的主要方法为:mkdir()根据抽

lamstudyingnet的专栏 497

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

【黑马程序员】java I/O 学习总结

---------- ASP.Net+Unity开发、.Net培训、期待与您交流! -------- /**  * (1)路径分隔符,一般在windows版本的java中使用正斜杠"/",如果使用反斜杠要转义"\\"  *   * (2)File的renameTo(File newName)方法不仅是重命名,还会根据newName中的路径移动  * 文件位置,无法跨文件系统,目标目录

进击的程序猿 549

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

黑马程序员_Java I/O 技术

------- android培训、java培训、期待与您交流! ---------- 输入/输出处理是程序设计中非常重要的一部分,比如从键盘读取数据、从文件中读取数据或向文件中写数据等等。Java把这些不同类型的输入、输出源抽象为流(stream),用统一接口来表示,从而使程序简单明了。 Jdk 提供了包java.io,其中包括一系列的类来实现输入/输出处理。进行I/O操作时可能会产

QQ153194574的专栏 620

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

黑马程序员——Java I/O

------- android培训、java培训、期待与您交流! ---------- Java I/O流系统流:流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样。IO流的概述:IO流用来处理设备之间的数据传输。Jav...

nigel521的专栏 192

黑马程序员Java I/O系统2

------- android培训、java培训、期待与您交流! ---------- 黑马程序员Java I/O系统2 装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。装饰模式可以在不创造更多子类的情况下,将对象的功能加以扩展。 若处理的数据量较多,为避免每个字节的读写都对流进行,可以使用过滤流类的子类缓冲流。缓冲流建立一个内部缓冲区,输入输出数据先读写到缓冲区中

lamstudyingnet的专栏 564

黑马程序员:java I/O流

------- android培训、java培训、期待与您交流! ---------- 模板

u011373068的专栏 559

黑马程序员—JAVA基础之I/O

IO流概述 IO流主要用来处理设备之间的数据传输。就是说通过java的语言来处理设备上的数据,比如硬盘上的文件,内存中的数据。早期这些操作数据的方法通过封装,便形成了IO流对象。纵多的IO对象就形成了IO包。按照流向分为两大类:一个是输入流,一个是输出流。按照操作的数据分类又分为:字符流,字节流。(所有的数据原始的状态还是字节数据。字符的出现主要是通过一串的字节数据来表示字符,最后形成了一个字节

yxqcz的专栏 590

【黑马程序员】java I/O流浅谈

----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------ 通过对I/O流的学习,让我懂得对于知识总结的重要性,通过总结可以让我对知识的理解更到位,而且对于知识点记忆的更加牢固, 一下是我通过学习教学视频中老师的总结所完成的对I/O流部分的总结: 因为流对象有很多,所以判断用哪个流对象就非常的重要~! 判断需要用什

u010036063的专栏 607

黑马程序员Java类之i/o流

---------------------- android培训、java培训、期待与您交流! ---------------------- 基本要点 1、 字符流与字节流,字节流不能处理Unicode,这个由字符流实现 2、 流的层次结构:建立在四个抽象类基础上 下面做一个字符输入流和字符输出流 package horse; import java.io.*; /**这是一个字符输

????的专栏 558

黑马程序员——java基础---I/O流

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- 一、I/O流概述   概念:I/O流用来处理设备之间的数据传输。Java对数据的操作是通过流的方式,而操作流的对象都放在IO包中。   分类:     按操作数据分为:字符流与字节流。     按流向分为:输入流与输出流。    IO流常用基类:   ...

Sa916487698的博客 324

《Java基础入门第2版》--黑马程序员 课后答案及其详解 第7章 I/O流

文章目录一、填空题二、判断题三、选择题四、简答题五、编程题六、原题及其解析 一、填空题 1、 字节流、字符流 2、 Channel、Buffer 3、 InputStreamReader、OutputStreamWriter 4、 Buffer、Channel、Selector 5、RandomAccesseFile 二、判断题 1、 错 2、对 3、对 4、对 5、错 三、选择题 1、AB 2、C 3、AB 4、A 5、B 四、简答题 1、Java程序通过I/O流来完成输

hypertext123的博客 1万+

黑马程序员——Java I/O基础知识之I/O流

android培训、java培训、期待与您交流! I/O流基础知识——字节流和字符流 文件存储在硬盘中,是以二进制表示的,只有内存中才能形成字符。数据的来源可以有硬盘,内存,控制台,网络,Java把数据从一个地方转到另一个地方的现象称为流,用InputStream和OutputStream接口来表示,这...

weixin_30871701的博客 150

黑马程序员 第五篇 Java I/O (foundation, completed)

Java I/O 详解 foundation

Das20pct的博客 658
上一篇: 黑马程序员-java集合框架
下一篇: 黑马程序员-java网络编程
LinsCode
博客等级 码龄13年 2粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值