FileOutputStream的空指针问题

周将 2019-09-17 05:56:36
目前在一个接收文件的demo遇到的问题,在多线程方法内:
FileOutputStream fos = null;

if (writeNum == 1) { // 第一次接收
firstFosWrite(file, byte[], fos);
}else{
fosWrite(byte[], fos);
}

private void firstFosWrite(File file, byte[] bytes, FileOutputStream fos) throws IOException {
System.out.println("**************第一次写文件*******************bytes" + bytes.length);
// file = new File(filePath);
fos = new FileOutputStream(file);
fos.write(bytes);
fos.flush();
}

private synchronized void fosWrite(byte[] bytes, FileOutputStream fos) throws IOException {
System.out.println("**************写文件*******************bytes" + bytes.length);
fos.write(bytes, 0, bytes.length);
fos.flush();
}

然而,在具体的使用过程中遇到了问题:firstFosWrite方法正常,fosWrite方法fos为空指针,请教大佬答疑。。。。。









另外,思考了其他方式,比如将FileOutputStream fos作为全局静态变量,但是这是在多线程内,这样做法是线程不安全的,只能保证单线程上传不出错,两个线程一起调用,文件数据就杂糅了
...全文
1264 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_39936465 2019-09-18
  • 打赏
  • 举报
回复
我觉得应该把IO变量和IO方法单独建一个类,然后线程构造引入IO类比较好,及不会发生上述情况,也方便方法同步加锁。
瘦死的黑骆驼 2019-09-18
  • 打赏
  • 举报
回复
引用 4 楼 周将 的回复:
[quote=引用 3 楼 瘦死的黑骆驼 的回复:] 上面的回答可能没有回答到点子上,你的意思我大概看明白了,你是想我第一次已经初始化过了,当第二次或更大次数时为什么fos依然是空的呢? 首先你没有理解java的内存模型,画一张图给你把 能看明白吗,你firstFosWrite方法的形参fos其实是重新在栈上开了一个引用(存储于虚拟机栈,线程安全的),两个开始都是null,然后你对后面一个赋值了,之前那个还是null,向下面这种最简单的代码,你试一下看看 public static void main(String[] args) { int i =7; System.out.println(i); } public static void tt(int i) { i = 9; } 改成这样就可以了 if (writeNum == 1) { // 第一次接收 fos = new FileOutputStream(file); firstFosWrite(file, byte[], fos); }else{ fosWrite(byte[], fos); } 多线程情况下直接到方法里去初始化,刚才也说过了,方法里的局部变量表是线程安全的,不需要两个方法,就一个方法就行了 private void fosWrite(File file, byte[] bytes) throws IOException { FileOutputStream fos = new FileOutputStream(file); fos.write(bytes); fos.flush(); }
你好,业务场景是这样的,两个write方法中的byte[]只是文件中的一部分,理想中的实现是,收到一部分byte[]就写入到文件中,文件只会越写越大,如果每次都初始化,这样操作是不是会导致文件始终只有最后写入的那一小部分?[/quote] 每次初始化写也没问题啊,FileOutputStream fos = new FileOutputStream(file, true);用这个构造函数,是追加写的
周将 2019-09-18
  • 打赏
  • 举报
回复
引用 3 楼 瘦死的黑骆驼 的回复:
上面的回答可能没有回答到点子上,你的意思我大概看明白了,你是想我第一次已经初始化过了,当第二次或更大次数时为什么fos依然是空的呢?
首先你没有理解java的内存模型,画一张图给你把

能看明白吗,你firstFosWrite方法的形参fos其实是重新在栈上开了一个引用(存储于虚拟机栈,线程安全的),两个开始都是null,然后你对后面一个赋值了,之前那个还是null,向下面这种最简单的代码,你试一下看看
public static void main(String[] args) {
int i =7;
System.out.println(i);
}

public static void tt(int i) {
i = 9;
}
改成这样就可以了
if (writeNum == 1) { // 第一次接收
fos = new FileOutputStream(file);
firstFosWrite(file, byte[], fos);
}else{
fosWrite(byte[], fos);
}
多线程情况下直接到方法里去初始化,刚才也说过了,方法里的局部变量表是线程安全的,不需要两个方法,就一个方法就行了
private void fosWrite(File file, byte[] bytes) throws IOException {
FileOutputStream fos = new FileOutputStream(file);
fos.write(bytes);
fos.flush();
}



你好,业务场景是这样的,两个write方法中的byte[]只是文件中的一部分,理想中的实现是,收到一部分byte[]就写入到文件中,文件只会越写越大,如果每次都初始化,这样操作是不是会导致文件始终只有最后写入的那一小部分?
周将 2019-09-18
  • 打赏
  • 举报
回复
引用 1 楼 oh_Maxy 的回复:
firstFosWrite 方法里的 fos = new FileOutputStream(file); 作用域,只在此方法内。
可以 firstFosWrite 返回类型改成 FileOutputStream , 主方法里: fos = firstFosWrite(...);

感谢讲解,不过我还是采用了在方法内初始化的方案,用了个之前没用过的构造方法
周将 2019-09-18
  • 打赏
  • 举报
回复
引用 6 楼 qq_39936465 的回复:
我觉得应该把IO变量和IO方法单独建一个类,然后线程构造引入IO类比较好,及不会发生上述情况,也方便方法同步加锁。

现在只是尝试,后期还是想用线程池的方式实现,到时候看吧
周将 2019-09-18
  • 打赏
  • 举报
回复
引用 5 楼 瘦死的黑骆驼 的回复:
[quote=引用 4 楼 周将 的回复:]
[quote=引用 3 楼 瘦死的黑骆驼 的回复:]
上面的回答可能没有回答到点子上,你的意思我大概看明白了,你是想我第一次已经初始化过了,当第二次或更大次数时为什么fos依然是空的呢?
首先你没有理解java的内存模型,画一张图给你把

能看明白吗,你firstFosWrite方法的形参fos其实是重新在栈上开了一个引用(存储于虚拟机栈,线程安全的),两个开始都是null,然后你对后面一个赋值了,之前那个还是null,向下面这种最简单的代码,你试一下看看
public static void main(String[] args) {
int i =7;
System.out.println(i);
}

public static void tt(int i) {
i = 9;
}
改成这样就可以了
if (writeNum == 1) { // 第一次接收
fos = new FileOutputStream(file);
firstFosWrite(file, byte[], fos);
}else{
fosWrite(byte[], fos);
}
多线程情况下直接到方法里去初始化,刚才也说过了,方法里的局部变量表是线程安全的,不需要两个方法,就一个方法就行了
private void fosWrite(File file, byte[] bytes) throws IOException {
FileOutputStream fos = new FileOutputStream(file);
fos.write(bytes);
fos.flush();
}



你好,业务场景是这样的,两个write方法中的byte[]只是文件中的一部分,理想中的实现是,收到一部分byte[]就写入到文件中,文件只会越写越大,如果每次都初始化,这样操作是不是会导致文件始终只有最后写入的那一小部分?[/quote]
每次初始化写也没问题啊,FileOutputStream fos = new FileOutputStream(file, true);用这个构造函数,是追加写的[/quote]

感谢答疑,已经解决了我的问题
瘦死的黑骆驼 2019-09-17
  • 打赏
  • 举报
回复
上面的回答可能没有回答到点子上,你的意思我大概看明白了,你是想我第一次已经初始化过了,当第二次或更大次数时为什么fos依然是空的呢? 首先你没有理解java的内存模型,画一张图给你把 能看明白吗,你firstFosWrite方法的形参fos其实是重新在栈上开了一个引用(存储于虚拟机栈,线程安全的),两个开始都是null,然后你对后面一个赋值了,之前那个还是null,向下面这种最简单的代码,你试一下看看 public static void main(String[] args) { int i =7; System.out.println(i); } public static void tt(int i) { i = 9; } 改成这样就可以了 if (writeNum == 1) { // 第一次接收 fos = new FileOutputStream(file); firstFosWrite(file, byte[], fos); }else{ fosWrite(byte[], fos); } 多线程情况下直接到方法里去初始化,刚才也说过了,方法里的局部变量表是线程安全的,不需要两个方法,就一个方法就行了 private void fosWrite(File file, byte[] bytes) throws IOException { FileOutputStream fos = new FileOutputStream(file); fos.write(bytes); fos.flush(); }
qybao 2019-09-17
  • 打赏
  • 举报
回复
如LS说,作用域不同,要么如LS说的,要么FileOutputStream fos = null;改为成员变量,方法不用fos参数
另外,多线程,firstFosWrite和writeNum估计也要加锁(不知道writeNum是不是成员变量,在哪里由哪个线程赋值)
oh_Maxy 2019-09-17
  • 打赏
  • 举报
回复
firstFosWrite 方法里的 fos = new FileOutputStream(file); 作用域,只在此方法内。
可以 firstFosWrite 返回类型改成 FileOutputStream , 主方法里: fos = firstFosWrite(...);

62,628

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧