在本文中,我们将为您详细介绍java基础——随机访问流的相关知识,并且为您解答关于java随机访问文件功能的疑问,此外,我们还会提供一些关于java基础——IO、Java基础——代码块、Java基础—
在本文中,我们将为您详细介绍java基础——随机访问流的相关知识,并且为您解答关于java随机访问文件功能的疑问,此外,我们还会提供一些关于java基础——IO、Java基础——代码块、Java基础——值传递、JAVA基础——内存流的有用信息。
本文目录一览:java基础——随机访问流(java随机访问文件功能)
package stream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import org.junit.jupiter.api.Test;
/*
* RandomAccessFile:随机读写访问流
* 既可以是输入流,也可以是输出流
* r|w|d|s:读|写|更新数据|元数据更新
*
* w:是对开头对文件内容进行覆盖
*
* */
public class RandomAccessFileTest {
@Test
public void test1(){
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try {
//1.流对象
raf1 = new RandomAccessFile(new File("hello.txt"),"r");
raf2 = new RandomAccessFile(new File("hello2.txt"),"rw");
//2.读写
byte[] buffer = new byte[1024];
int len;
while((len = raf1.read(buffer))!=-1) {
raf2.write(buffer,0,len);
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if(raf1!=null)
raf1.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
if(raf2!=null)
raf2.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*
* seek随机访问|插入方法
*
* */
@Test
public void test2() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello.txt", "rw");
/*raf1.seek(3);
raf1.write("abc".getBytes());
*/
/*
* 使用StringBuilder
* */
StringBuilder sb = new StringBuilder((int)(new File("hello.txt").length()));
raf1.seek(3L);
int len;
byte[] buffer = new byte[20];
//把后面的存起来
while((len = raf1.read(buffer))!=-1) {
sb.append(new String(buffer,0,len));
}
raf1.seek(3L);
//转换成字节写入
raf1.write("周恩杰".getBytes());
raf1.write(sb.toString().getBytes());
raf1.close();
}
}
java基础——IO
java类库创建了大量的io类来满足各种io端相互通信的需求。io是以流的输入输出为基础的,屏蔽了各种设备的实现细节。
一、InputStream
InputStream为输入流的基类,它的子类表示了不同数据源的输入流。
- 数据源为字节数组ByteArrayInputStream.可以作为内存缓冲区,从里面读取字节。
- 数据源为String对象的StringBufferInputStream,将字符串转换成输入流。
- 数据源为文件的FIleInputStream.
- "管道"PipedInputStream作为多线程的数据源,一端输入,另一端输出。
- SequenceInputStream将多个输入流合并成一个流。
- 其他数据源,如internet.
在使用InputStream时很少使用单一的流对象,而是使用装饰器输入流FilterInputStream组合多个对象来使用。FilterInputStream类型:
- DataInputStream可以以流的形式读取基本数据类型(int,char,long等)。
- BufferedInputStream代表使用"缓冲区"进行读取。
- LineNumberInputStream跟踪输入流中的行号,使用getLineNumber()和setLineNumber(int numer).
- PusheBackInputStream具有"能弹出一个字节的缓冲区",可以将最后读到的一个字节回退,通常作为编译器的扫描器。
二、OutputStream
OutputStream为输出流的基类,它的子类表示了不同数据源的输出流,输出流决定了输出的目标:字节数组、文件、管道。
- ByteArrayOutputStream为要输出的"流"的数据在内存中创建缓冲区。
- FileOutputStream文件输出流。
- PipedInputStream管道输出流。
而OutputStream一般也使用FilterOutputStream来组合多个对象提供输出功能。FilterInputStream类型:
- DataOutputStream与DataInputStream对应,想输出流中写入基本数据类型。
- PrintStream格式化输出。
- BufferedOutputStream表示使用"缓冲区"输出数据,可以用flush()清空缓冲区。可以指定缓冲区大小。
三、Reader和Writer
Reader和Writer提供了字符的输入和输出功能,InputStreamReader可以把InputStream转换为Reader,OutputStreamWriter可以把OutputStream转换为Writer。他们之间的具体转换如下:
InputStream | Reader,适配器:InputStreamReader |
OutputStream | Writer,适配器:OutputStreamWriter |
FileInputStream | FileReader |
FileOutputStream | FileWriter |
StringBufferInputStream | StringReader |
无对应 | StringWriter |
ByteArrayInputStream | CharArrayReader |
ByteArrayOutputStream | CharArrayWriter |
PiedInputStream | PiedReader |
PiedOutputStream | PiedWriter |
四、RandomAccessFile
RandomAccessFile不是InputStream或OutputStream的继承,而是一个独立的文件读写类,适用于大小已知的记录组成的文件,可以用seek()方法将记录从一处转到另一处。同时它支持搜索方法,并且只适用于文件。1.4后它的大部分功能由nio存储映射文件替代
五、nio
nio使用缓冲器ByteBuffer在通道之间传输数据,i/o中有三个类可以产生FileChannal,分别是FileInputStream,FileOutputStream和RandomAccessFile.可以向通道传递用于读写的ByteBuffer.
六、aio
Java基础——代码块
代码块:在类或方法中直接使用 “{ }”括起来的一段代码,表示一块代码区域。
代码块里变量属于局部变量,只在自己所在区域{ }内有效。
代码块依据位置不同分为三种形式:
- 局部代码块:直接定义在方法内部的代码块。一般不直接使用,常结合if /for语句中使用的局部代码块。
局部代码块程序示例:
public class CodeBlock { public static void main(String[] args) { int a=1; { int b=2; System.out.println(a); System.out.println(b); } System.out.println(a); // System.out.println(b); //此处b无法输出 } }
局部代码块程序示例运行结果:
1 2 1
- 初始化代码块(构造代码块):直接定义在类中。每次创建对象都会执行初始化代码块,每次创建对象都会调用构造器。在调用构造器之前,会先执行本类中的初始化代码块。(通过反编译后,会发现初始化代码块也作为构造器的最初语句。)
初始化代码块程序示例:
-
public class CodeBlock { { System.out.println("初始化代码块##########"); } CodeBlock(){ //构造器 System.out.println("构造器!!!!!!!!!"); } public static void main(String[] args) { new CodeBlock(); System.out.println("~~~~~~~~~~~"); new CodeBlock(); } }
初始化代码块程序示例运行结果:
初始化代码块########## 构造器!!!!!!!!! ~~~~~~~~~~~ 初始化代码块########## 构造器!!!!!!!!!
-
静态代码块(使用static修饰的代码块):在主方法执行之前执行静态代码块,且执行一次。
静态代码块程序示例:
public class CodeBlock {
{
System.out.println("初始化代码块##########");
}
CodeBlock(){ //构造器
System.out.println("构造器!!!!!!!!!");
}
static{ //静态代码块A
System.out.println("静态代码块A:$$$$$$$$$$");
}
public static void main(String[] args) {
new CodeBlock();
System.out.println("~~~~~~~~~~~");
new CodeBlock();
}
static{ //静态代码块B
System.out.println("静态代码块B:$$$$$$$$$$");
}
}
静态代码块程序示例运行结果:
静态代码块A:$$$$$$$$$$
静态代码块B:$$$$$$$$$$
初始化代码块##########
构造器!!!!!!!!!
~~~~~~~~~~~
初始化代码块##########
构造器!!!!!!!!!
Java基础——值传递
值传递?
参数传递的值的拷贝,改变拷贝不影响原参数。
引用传递?
参数传递的是参数本身,改变形参,实参也改变。
Java中是什么传递?
Java中只有值传递
实际情况为什么不对呢?
1. 基本数据类型
1 public class Main {
2
3
4 void method01(int a ){
5 a++;
6 System.out.println("a in method01 is "+a);
7 }
8
9 public static void main(String[] args) {
10 Main main = new Main();
11 int a = 12;
12
13 main.method01(a);
14 System.out.println(a);
15
16
17 }
18 }
输出结果:
a in method01 is 13
12
没有问题,原值没有改变。
2. String类型
1 public class Main {
2
3 void method02(String s){
4 s = "world";
5 System.out.println("string in method is "+s);
6
7 }
8
9
10 public static void main(String[] args) {
11 Main main = new Main();
12
13 String s = "hello";
14
15 main.method02(s);
16 System.out.println(s);
17
18
19 }
20 }
输出结果:
string in method is world
hello
没有问题,是值传递。原值没有改变
3. 自定义类
public class Main {
void method03(Cat cat){
cat.setName("haha");
System.out.println("cats name is "+cat.getName());
}
public static void main(String[] args) {
Main main = new Main();
Cat cat = new Cat();
cat.setName("mimi");
main.method03(cat);
System.out.println("cats name in main is "+cat.getName());
}
}
class Cat{
String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
输出结果:
cats name is haha
cats name in main is haha
不对!为什么值传递原值改变了??????
注意了,这里虽然原值改变了,但是还是值传递。为什么呢?
因为传递的是参数的引用的拷贝也是值传递,这里的值指的是地址的拷贝。
这里举一个简单的例子(引用地址:https://www.cnblogs.com/wchxj/p/8729503.html)
值传递:你有一把钥匙,当你的朋友想要去你家的时候,你复刻了一把新钥匙给他,自己的还在自己手里,这就是值传递。这种情况下,他对这把钥匙做什么都不会影响你手里的这把钥匙。
引用传递:你有一把钥匙,当你的朋友想要去你家的时候,如果你直接把你的钥匙给他了,这就是引用传递。这种情况下,如果他对这把钥匙做了什么事情,比如他在钥匙上刻下了自己名字,那么这把钥匙还给你的时候,你自己的钥匙上也会多出他刻的名字。
当你使用值传递,拷贝一份钥匙给你朋友后,你朋友在你家砸了电视,那么你回家的时候电视肯定是被砸了的。
这个例子理解起来就容易多了。按照这个逻辑我们来测验一下。
如果Java传递的只是引用的拷贝的话,我们将形参指向null,那么实参不会受到影响。通过上面的例子来解释就是,如果你给你朋友的钥匙只是一把复制的钥匙的话,我们将朋友手上的钥匙摧毁,我们还是能通过钥匙原件开门。
public class Main {
void method04(Cat cat){
//摧毁朋友手中的钥匙
cat = null;
try {
System.out.println(cat.getName());
}catch (Exception e){
e.printStackTrace();
System.out.println("cat 已经被回收!");
}
}
public static void main(String[] args) {
Main main = new Main();
Cat cat = new Cat();
cat.setName("mimi");
main.method04(cat);
System.out.println(cat.getName());
}
}
class Cat{
String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
输出结果:
java.lang.NullPointerException
at Main.method04(Main.java:21)
at Main.main(Main.java:44)
cat 已经被回收!
new name
没错!就是这样。
所以Java中只有值传递。
JAVA基础——内存流
掌握内存操作流
输入和输出都是从文件中来的,当然,也可将输出的位置设置在内存上,这就需要ByteArrayInputStream和ByteArrayOutputStream
ByteArrayInputStream:将内容写入到内存中,
ByteArrayOutputStream:将内存中数据输出
此时的操作应该以内存为操作点。
利用此类 完成一些功能。
常用方法
ByteArrayInputStream :是InputStream子类。
public class ByteArrayInputStream extends InputStream
构造方法:
ByteArrayInputStream(byte[] buf)
创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。
接收一个byte数组,实际上内存的输入就是在构造方法上将数据传递到内存之中。
ByteArrayOutputStream:是OutputStream子类
输出就是从内存中写出数据。
public class ByteArrayOutputStream extends OutputStream
构造方法:
ByteArrayOutputStream()
创建一个新的 byte 数组输出流。
主要方法:
void write(int b)
将指定的字节写入此 byte 数组输出流。
利用他们,完成一个大小写字母转换顺序的程序。
重温一下这个方法:getBytes();定义如下:返回的是一个byte类型的数组。
public byte[] getBytes() {
return StringCoding.encode(value, 0, value.length);
}
1,
int size()
返回缓冲区的当前大小
2,
byte[] toByteArray()
创建一个新分配的 byte 数组。
3,
String toString()
使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。
利用他们,完成一个大小写字母转换顺序的程序。
String类的大小写转换方法:
String toLowerCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
转大写:
String toUpperCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
如果要想把一个大写边小写,则可以通过包装类,字符的包装类是Character。
static char toLowerCase(char ch)
使用取自 UnicodeData 文件的大小写映射信息将字符参数转换为小写。
代码实例:
注意,跟文件读取不一样,不要设置文件路径。


package 类集;
import java.io.* ;
public class ByteArrayDemo01{
public static void main(String args[]){
String str = "HELLOWORLD" ; // 定义一个字符串,全部由大写字母组成
ByteArrayInputStream bis = null ; // 内存输入流
ByteArrayOutputStream bos = null ; // 内存输出流
bis = new ByteArrayInputStream(str.getBytes()) ; // 向内存中输出内容,注意,没有跟文件读取一样,设置文件路径。
bos = new ByteArrayOutputStream() ; // 准备从内存ByteArrayInputStream中读取内容,注意,跟文件读取不一样,不要设置文件路径。
int temp = 0 ; while((temp=bis.read())!=-1) { char c = (char) temp ; // 读取的数字变为字符 bos.write(Character.toLowerCase(c)) ; // 将字符变为小写 } // 所有的数据就全部都在ByteArrayOutputStream中 String newStr = bos.toString() ; // 因为所有output的数据都在ByteArrayOutputStream实例对象中,所以可以取出内容,将缓冲区内容转换为字符串。
try{ bis.close() ; bos.close() ; }catch(IOException e){ e.printStackTrace() ; } System.out.println(newStr) ; } };


实际上以上操作很好体现了对象的多态。通过实例化其子类不同,完成的功能也不同,也就相当于输出的位置不同,
如果是输出文件,则使用FileXxxx类。如果是内存,则使用ByteArrayXxx。
关于java基础——随机访问流和java随机访问文件功能的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于java基础——IO、Java基础——代码块、Java基础——值传递、JAVA基础——内存流等相关知识的信息别忘了在本站进行查找喔。
本文标签: