Я пытаюсь работать с функцией передачи файлов для моего приложения. Моя реализация передачи файлов заключается в том, чтобы отправить файл по частям в виде объектов, содержащих информацию о файле, а также отправленные байты. Тем не менее, я заметил, что могу писать только в файл, если я сохраню все полученные байты в списке, а затем сразу же напишу его в файл. Если я попытаюсь записать файл по частям, он попадет в пустой файл, как если бы файл вообще не был написан.FileOutputStream по частям не работает
Вот мой метод, который читает исходный файл, а затем отправляет его по частям:
public void sendFile(File src) {
try {
BufferedInputStream is = new BufferedInputStream(new FileInputStream(src));
Message msg = new Message(MType.FILE_OPEN, true);
com.transmit(msg);
byte[] buf = new byte[Utility.bufferSize];
msg = new Message(MType.FILE_NAME, src.getName());
msg.setValue(MType.FILE_SIZE, Files.size(src.toPath()));
com.transmit(msg);
for (int count = is.read(buf); count > 0; count = is.read(buf)) {
msg = new Message(MType.FILE_NAME, src.getName());
msg.setValue(MType.FILE_SIZE, Files.size(src.toPath()));
msg.setValue(MType.FILE_BYTE, buf);
msg.setValue(MType.FILE_COUNT, count);
com.transmit(msg);
}
msg = new Message(MType.FILE_NAME, src.getName());
msg.setValue(MType.FILE_SIZE, Files.size(src.toPath()));
msg.setValue(MType.FILE_CLOSE, true);
is.close();
com.transmit(msg);
} catch (IOException e) {
sender.getChatRoomController().error(ProgramError.ATTACH_FILE);
Utility.log(e);
e.printStackTrace();
}
}
Вот мой метод, который принимает сообщение объекты на другом конце:
public void readFile(Message msg) {
if (msg.hasID(MType.FILE_NAME)) {
String name = msg.getValue(MType.FILE_NAME).toString();
long size = (long) msg.getValue(MType.FILE_SIZE);
File file = new File(Directories.fDir.getDirectory(), name);
TempFile tf = new TempFile(file);
if (!map.containsKey(file)) {
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
map.put(file, tf);
} else {
tf = map.get(file);
}
if (msg.hasValue(MType.FILE_BYTE)) {
byte[] buf = (byte[]) msg.getValue(MType.FILE_BYTE);
int count = (int) msg.getValue(MType.FILE_COUNT);
tf.addEntry(buf, count);
}
if (msg.hasValue(MType.FILE_CLOSE)) {
tf.writeFile(true);
map.remove(file);
if (sender instanceof Server) {
Server server = (Server) sender;
msg = new Message(MType.FILE_NAME, name);
msg.setValue(MType.FILE_SIZE, size);
msg.setValue(MType.FILE_ATTACHMENT, server.getFileID());
addFile(file, server);
server.broadcast(msg);
}
}
}
}
И здесь мой класс TempFile:
public class TempFile {
private ArrayList<Byte[]> data;
private ArrayList<Integer> counts;
private File file;
public TempFile(File file) {
data = new ArrayList<>();
counts = new ArrayList<>();
this.file = file;
}
public void addEntry(byte[] data, int count) {
this.data.add(Utility.toWrapper(data));
this.counts.add(count);
}
public void writeFile(boolean append) {
try {
BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file));
for (int i = 0; i < data.size(); i++) {
byte[] chunk = Utility.toPrimitive(data.get(i));
int count = counts.get(i);
os.write(chunk, 0, count);
}
os.flush();
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
И вот моя другая реализация, которая включает в себя действие ual temp files:
public class TempFile2 {
private File file;
private File tempFile;
private FileOutputStream os;
public TempFile2(File file) {
this.file = file;
this.tempFile = new File(file.getParent(), FilenameUtils.getBaseName(file.getName()) + ".tmp");
if (!tempFile.exists()) {
try {
tempFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
os = new FileOutputStream(tempFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public void addEntry(byte[] data, int count) {
try {
os.write(data, 0, count);
} catch (IOException e) {
e.printStackTrace();
}
}
public void writeFile() {
try {
os.close();
Files.copy(tempFile.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Являются ли оба файла .tmp и окончательный файл пустыми? –
Вы добавляете все записи в «ArrayList <> данные в памяти», а затем, когда вы на самом деле пишете в «OutputStream» в своем классе «TempFile», вы повторяете и выполняете только 'os.write' в цикле. Вы только 'os.flush' вне этого цикла. Таким образом, да, это только очистит то, что вы написали в буфере «OutputStream», когда вы закончите запись всех записей файла или до тех пор, пока данные не превысят встроенный лимит. Выполнение флеша после каждой записи может повлечь за собой штрафные санкции ввода-вывода за ваш код, но, возможно, сделать флеш после каждых n записей. –