gpt4 book ai didi

Java 在通过 Windows 远程桌面 (tsclient) 写入时创建巨大的文件

转载 作者:太空狗 更新时间:2023-10-29 22:41:23 25 4
gpt4 key购买 nike

当我们的 Swing 应用程序通过 Windows 远程桌面(该应用程序托管在用户连接的终端服务器上)向用户本地计算机写入文件时,我们的一位客户报告了一个非常奇怪的问题。

流程是:

  • 用户通过远程桌面登录并运行应用程序(将他们的 C:\ 作为“本地资源”包含在内)
  • 在工作时,他们将数据从数据库导出到文件
  • 用户选择要导出的数据
  • 用户在他们的本地计算机上选择一个目标文件,如 \\tsclient\C\Temp\TestFile.txt
  • 文件可能很大,因此每批从数据库中提取 1000 行并写入文件
  • 在第二批中,当 Java 打开文件并再次写入时,一些非常奇怪的事情开始发生!
    • 文件的大小迅速增加并在 2 GB 左右停止
    • 然后数据继续写入文件

我不确定这是否是核心 Java 库、远程桌面实现或组合中的问题。我们的应用程序也通过运行良好的 Citrix 托管,写入本地磁盘或 UNC 网络路径也运行良好。

我创建了一个 SSCCE演示该问题,使用远程桌面连接到计算机(确保 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;
}
}

最佳答案

我没有设置(没有 Windows)来验证这种效果 :( 所以只是想:

2GB 听起来像是文件系统相关的最大文件大小。您客户端的 32 位 Windows 操作系统?

这种行为听起来像是在坏 block FS 上聪明的文件系统缓存:大块的快速文件远程写入访问试图巧妙地全神贯注于文件,以试图加快对具有 block 的文件的 future 写入。尝试不同的 FS 来验证? Tried FreeRDP?

保持文件打开。重新打开写入大块可能会提示智能系统进行缓存。

更新:

FileChannelImpl.java:248

// in append-mode then position is advanced to end before writing
p = (append) ? nd.size(fd) : position0(fd, -1);

最终导致 FileDispatcherImpl:136

static native long More ...size0(FileDescriptor fd) throws IOException;

作为原生的东西可以容纳任何错误。当涉及到中间的协议(protocol)时。我宁愿将其作为 nio/Windows 中的错误来归档,因为他们可能没有预见到 RDP 底层有任何有趣的事情。

看起来返回的大小是 Integer.MAX_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 在通过 Windows 远程桌面 (tsclient) 写入时创建巨大的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20351683/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com