通过Windows远程桌面(tsclient)写入时,Java会创建巨大的文件
当我们的Swing应用程序通过Windows远程桌面(应用程序托管在用户连接的终端服务器上)向用户本地计算机写入文件时,我们的一个客户端报告了一个非常奇怪的问题 流程是:通过Windows远程桌面(tsclient)写入时,Java会创建巨大的文件,java,windows,file-io,remote-desktop,Java,Windows,File Io,Remote Desktop,当我们的Swing应用程序通过Windows远程桌面(应用程序托管在用户连接的终端服务器上)向用户本地计算机写入文件时,我们的一个客户端报告了一个非常奇怪的问题 流程是: 用户通过远程桌面登录并运行应用程序(其C:\包含在“本地资源”中) 在工作时,他们将数据从数据库导出到文件中 用户选择要导出的数据 用户在本地计算机上选择目标文件,如\\tsclient\C\Temp\TestFile.txt 文件可能很大,所以每批从数据库中提取1000行并写入文件 在第二批中,当Java打开文件并再次写入
- 用户通过远程桌面登录并运行应用程序(其
包含在“本地资源”中)C:\
- 在工作时,他们将数据从数据库导出到文件中
- 用户选择要导出的数据
- 用户在本地计算机上选择目标文件,如
\\tsclient\C\Temp\TestFile.txt
- 文件可能很大,所以每批从数据库中提取1000行并写入文件
- 在第二批中,当Java打开文件并再次写入时,一些非常奇怪的事情开始发生了!
- 该文件的大小迅速增加,并在2GB左右停止
- 然后数据继续写入文件
C:\
是“本地资源”),然后运行该程序以查看一些非常奇怪的行为!我使用的是JDK-7u45
import static java.nio.file.StandardOpenOption.APPEND;
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static java.nio.file.StandardOpenOption.WRITE;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.util.Collections;
/**
* Demonstrates weird issue when writing (appending) to a file over TsClient (Microsoft Remote Desktop).
*
* @author Martin
*/
public class WriteOverTsClientDemo
{
private static final File FILE_TO_WRITE = new File("\\\\tsclient\\C\\Temp\\TestFile.txt");
//private static final File FILE_TO_WRITE = new File("C:\\Temp\\TestFile.txt");
private static final String ROW_DATA = "111111111122222222223333333333444444444555555555566666666667777777777888888888899999999990000000000";
public static void main(String[] args) throws IOException
{
if (!FILE_TO_WRITE.getParentFile().exists())
{
throw new RuntimeException("\nPlease create directory C:\\Temp\\ on your local machine and run this application via RemoteDesktop with C:\\ as a 'Local resource'.");
}
FILE_TO_WRITE.delete();
new WriteOverTsClientDemo().execute();
}
private void execute() throws IOException
{
System.out.println("Writing to file: " + FILE_TO_WRITE);
System.out.println();
for (int i = 1; i <= 10; i++)
{
System.out.println("Writing batch " + i + "...");
writeDataToFile(i);
System.out.println("Size of file after batch " + i + ": " + FILE_TO_WRITE.length());
System.out.println();
}
System.out.println("Done!");
}
private void writeDataToFile(int batch) throws IOException
{
Charset charset = Charset.forName("UTF-8");
CharsetEncoder encoder = charset.newEncoder();
try(OutputStream out = Files.newOutputStream(FILE_TO_WRITE.toPath(), CREATE, WRITE, getTruncateOrAppendOption(batch));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, encoder)))
{
writeData(batch, writer);
}
}
private void writeData(int batch, BufferedWriter writer) throws IOException
{
for (String data : createData())
{
writer.append(Integer.toString(batch));
writer.append(" ");
writer.append(data);
writer.append("\n");
}
}
private Iterable<String> createData()
{
return Collections.nCopies(100, ROW_DATA);
}
/**
* @return option to write from the beginning or from the end of the file
*/
private OpenOption getTruncateOrAppendOption(int batch)
{
return batch == 1 ? TRUNCATE_EXISTING : APPEND;
}
}
导入静态java.nio.file.StandardOpenOption.APPEND;
导入静态java.nio.file.StandardOpenOption.CREATE;
导入静态java.nio.file.StandardOpenOption.TRUNCATE_;
导入静态java.nio.file.StandardOpenOption.WRITE;
导入java.io.BufferedWriter;
导入java.io.File;
导入java.io.IOException;
导入java.io.OutputStream;
导入java.io.OutputStreamWriter;
导入java.nio.charset.charset;
导入java.nio.charset.CharsetEncoder;
导入java.nio.file.Files;
导入java.nio.file.OpenOption;
导入java.util.Collections;
/**
*演示通过TsClient(Microsoft远程桌面)写入(附加)文件时出现的奇怪问题。
*
*@作者马丁
*/
公共类WriteOverTsClientDemo
{
私有静态最终文件File TO WRITE=新文件(\\\\tsclient\\C\\Temp\\TestFile.txt);
//私有静态最终文件File_TO_WRITE=新文件(“C:\\Temp\\TestFile.txt”);
私有静态最终字符串行_DATA=“1111111 22222222 3333333 444444444 55555555 66666666 77777777 8888888 9999990000000000”;
公共静态void main(字符串[]args)引发IOException
{
如果(!FILE_TO_WRITE.getParentFile().exists())
{
抛出新的RuntimeException(“\n请在本地计算机上创建目录C:\\Temp\,并通过RemoteDesktop将C:\\作为“本地资源”运行此应用程序”;
}
文件_TO_WRITE.delete();
新建WriteOverTsClientDemo().execute();
}
私有void execute()引发IOException
{
System.out.println(“写入文件:+文件写入”);
System.out.println();
对于(int i=1;i我没有验证此效果的设置(没有窗口):(所以只考虑:
2GB听起来像是客户端与文件系统相关的最大文件大小.32位Windows操作系统
这种行为听起来像是在坏块FS上进行聪明的文件系统缓存:远程对大块的快速文件写入访问尝试聪明地占用文件,以尝试将将来对具有块的文件的写入固定在一起。是否尝试使用不同的FS进行验证
保持文件打开。重新打开以写入大型块可能会提示聪明的系统进行缓存
更新:
最终导致
作为本机的东西可以容纳任何bug。当涉及到中间的protocoll时。我宁愿在nio/Windows中将其作为bug归档,因为他们可能没有预见到RDP下面有任何有趣的事情
看起来返回的大小是Integer.MAX\u VALUE
,文件指针移到了那里
替代实现java.io.FileWriter
,不编码以减少代码行:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
/**
* Demonstrates weird issue when writing (appending) to a file over TsClient (Microsoft Remote Desktop).
*
* @author Martin
*/
public class WriteOverTsClientDemo
{
// private static final File FILE_TO_WRITE = new File("\\\\tsclient\\C\\Temp\\TestFile.txt");
private static final File FILE_TO_WRITE = new File("/tmp/TestFile.txt");
private static final String ROW_DATA = "111111111122222222223333333333444444444555555555566666666667777777777888888888899999999990000000000";
public static void main(final String[] args) throws IOException
{
if (!FILE_TO_WRITE.getParentFile().exists())
{
throw new RuntimeException("\nPlease create directory C:\\Temp\\ on your local machine and run this application via RemoteDesktop with C:\\ as a 'Local resource'.");
}
FILE_TO_WRITE.delete();
new WriteOverTsClientDemo().execute();
}
private void execute() throws IOException
{
System.out.println("Writing to file: " + FILE_TO_WRITE);
System.out.println();
for (int i = 1; i <= 20; i++)
{
System.out.println("Writing batch " + i + "...");
writeDataToFile(i);
System.out.println("Size of file after batch " + i + ": " + FILE_TO_WRITE.length());
System.out.println();
}
System.out.println("Done!");
}
private void writeDataToFile(final int batch) throws IOException
{
try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_TO_WRITE, batch > 1)))
{
writeData(batch, writer);
}
}
private void writeData(final int batch, final BufferedWriter writer) throws IOException
{
for (final String data : createData())
{
writer.append(Integer.toString(batch));
writer.append(" ");
writer.append(data);
writer.append("\n");
}
}
private Iterable<String> createData()
{
return Collections.nCopies(100, ROW_DATA);
}
}
导入java.io.BufferedWriter;
导入java.io.File;
导入java.io.FileWriter;
导入java.io.IOException;
导入java.util.Collections;
/**
*演示通过TsClient(Microsoft远程桌面)写入(附加)文件时出现的奇怪问题。
*
*@作者马丁
*/
公共类WriteOverTsClientDemo
{
//私有静态最终文件File TO WRITE=新文件(\\\\tsclient\\C\\Temp\\TestFile.txt);
私有静态最终文件File_TO_WRITE=新文件(“/tmp/TestFile.txt”);
私有静态最终字符串行_DATA=“1111111 22222222 3333333 444444444 55555555 66666666 77777777 8888888 9999990000000000”;
公共静态void main(最终字符串[]args)引发IOException
{
如果(!FILE_TO_WRITE.getParentFile().exists())
{
抛出新的RuntimeException(“\n请在本地计算机上创建目录C:\\Temp\,并通过RemoteDesktop将C:\\作为“本地资源”运行此应用程序”;
}
文件_TO_WRITE.delete();
新建WriteOverTsClientDemo().execute();
}
私有void execute()引发IOException
{
System.out.println(“写入文件:+文件写入”);
System.out.println();
对于(int i=1;i 1)))
{
writeData(批处理、写入程序);
}
}
私有void writeData(最终int批处理,最终BufferedWriter writer)引发IOException
{
for(最终字符串数据:createData())
{
writer.append(Integer.toString(batch));
作者。追加(“”);
writer.append(数据);
writer.append(“\n”);
}
}
私有Iterable createData()
{
返回集合.nCopies(100行,数据);
}
}
我们遇到了完全相同的问题,一位客户报告说,我们的java应用程序在写入TS客户端共享驱动器时会创建2GB文件。
我们注意到,只有在附加d时才会出现问题
static native long More ...size0(FileDescriptor fd) throws IOException;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
/**
* Demonstrates weird issue when writing (appending) to a file over TsClient (Microsoft Remote Desktop).
*
* @author Martin
*/
public class WriteOverTsClientDemo
{
// private static final File FILE_TO_WRITE = new File("\\\\tsclient\\C\\Temp\\TestFile.txt");
private static final File FILE_TO_WRITE = new File("/tmp/TestFile.txt");
private static final String ROW_DATA = "111111111122222222223333333333444444444555555555566666666667777777777888888888899999999990000000000";
public static void main(final String[] args) throws IOException
{
if (!FILE_TO_WRITE.getParentFile().exists())
{
throw new RuntimeException("\nPlease create directory C:\\Temp\\ on your local machine and run this application via RemoteDesktop with C:\\ as a 'Local resource'.");
}
FILE_TO_WRITE.delete();
new WriteOverTsClientDemo().execute();
}
private void execute() throws IOException
{
System.out.println("Writing to file: " + FILE_TO_WRITE);
System.out.println();
for (int i = 1; i <= 20; i++)
{
System.out.println("Writing batch " + i + "...");
writeDataToFile(i);
System.out.println("Size of file after batch " + i + ": " + FILE_TO_WRITE.length());
System.out.println();
}
System.out.println("Done!");
}
private void writeDataToFile(final int batch) throws IOException
{
try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_TO_WRITE, batch > 1)))
{
writeData(batch, writer);
}
}
private void writeData(final int batch, final BufferedWriter writer) throws IOException
{
for (final String data : createData())
{
writer.append(Integer.toString(batch));
writer.append(" ");
writer.append(data);
writer.append("\n");
}
}
private Iterable<String> createData()
{
return Collections.nCopies(100, ROW_DATA);
}
}
#include <windows.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc < 2) {
printf("Not enough args\n");
return 1;
}
HANDLE hFile = CreateFile(argv[1], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD nw;
OVERLAPPED ov;
ov.Offset = (DWORD)0xFFFFFFFF;
ov.OffsetHigh = (DWORD)0xFFFFFFFF;
ov.hEvent = NULL;
WriteFile(hFile, "a", 1, &nw, &ov);
CloseHandle(hFile);
return 1;
}