热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

从Firefox复制并在Ubuntu中使用Java读取时,剪贴板内容会混乱

如何解决《从Firefox复制并在Ubuntu中使用Java读取时,剪贴板内容会混乱》经验,为你挑选了1个好方法。

背景

我正在尝试使用Java获取HTML数据风格的剪贴板数据.因此我将它们从浏览器复制到剪贴板中.然后我使用java.awt.datatransfer.Clipboard来获取它们.

这在Windows系统中正常工作.但在Ubuntu中存在一些奇怪的问题.最糟糕的是从Firefox浏览器将数据复制到剪贴板.

再现行为的示例

Java代码:

import java.io.*;

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;

public class WorkingWithClipboadData {

 static void doSomethingWithBytesFromClipboard(byte[] dataBytes, String paramCharset, int number) throws Exception {

  String fileName = "Result " + number + " " + paramCharset + ".txt";

  OutputStream fileOut = new FileOutputStream(fileName);
  fileOut.write(dataBytes, 0, dataBytes.length);
  fileOut.close();

 }

 public static void main(String[] args) throws Exception {

  Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();

  int count = 0;

  for (DataFlavor dataFlavor : clipboard.getAvailableDataFlavors()) {

System.out.println(dataFlavor);

   String mimeType = dataFlavor.getHumanPresentableName();
   if ("text/html".equalsIgnoreCase(mimeType)) {
    String paramClass = dataFlavor.getParameter("class");
    if ("java.io.InputStream".equals(paramClass)) {
     String paramCharset = dataFlavor.getParameter("charset");
     if (paramCharset != null  && paramCharset.startsWith("UTF")) {

System.out.println("============================================");
System.out.println(paramCharset);
System.out.println("============================================");

      InputStream inputStream = (InputStream)clipboard.getData(dataFlavor);

      ByteArrayOutputStream data = new ByteArrayOutputStream();

      byte[] buffer = new byte[1024];
      int length = -1;
      while ((length = inputStream.read(buffer)) != -1) {
       data.write(buffer, 0, length);
      }
      data.flush();
      inputStream.close();

      byte[] dataBytes = data.toByteArray();
      data.close();

      doSomethingWithBytesFromClipboard(dataBytes, paramCharset, ++count);

     }
    }
   }
  }
 }

}

问题描述

我正在做的是,在Firefox中打开URL https://en.wikipedia.org/wiki/Germanic_umlaut.然后我在那里选择"letters:ä"并将其复制到剪贴板中.然后我运行我的Java程序.之后,生成的文件(仅其中一些作为示例)如下所示:

axel@arichter:~/Dokumente/JAVA/poi/poi-3.17$ xxd "./Result 1 UTF-16.txt" 
00000000: feff fffd fffd 006c 0000 0065 0000 0074  .......l...e...t
00000010: 0000 0074 0000 0065 0000 0072 0000 0073  ...t...e...r...s
00000020: 0000 003a 0000 0020 0000 003c 0000 0069  ...:... ...<...i
00000030: 0000 003e 0000 fffd 0000 003c 0000 002f  ...>.......<.../
00000040: 0000 0069 0000 003e 0000                 ...i...>..

好的FEFF,开头看起来像一个UTF-16BE字节顺序标记.但那是什么FFFD?为什么0000单个字母之间有那些字节?UTF-16的编码l006C仅仅.似乎所有字母都以32位编码.但这是错误的UTF-16.并且所有非ASCII字符都被编码,FFFD 0000因此丢失.

axel@arichter:~/Dokumente/JAVA/poi/poi-3.17$ xxd "./Result 4 UTF-8.txt" 
00000000: efbf bdef bfbd 6c00 6500 7400 7400 6500  ......l.e.t.t.e.
00000010: 7200 7300 3a00 2000 3c00 6900 3e00 efbf  r.s.:. .<.i.>...
00000020: bd00 3c00 2f00 6900 3e00                 ..<./.i.>.

这里EFBF BDEF BFBD看起来不像任何已知的字节顺序标记.并且所有字母似乎都以16位编码,这是所需位的两倍UTF-8.所以使用的位似乎总是需要的双重计数.参见UTF-16上面的例子.并且所有非ASCII字母都被编码为EFBFBD,因此也丢失了.

axel@arichter:~/Dokumente/JAVA/poi/poi-3.17$ xxd "./Result 7 UTF-16BE.txt" 
00000000: fffd fffd 006c 0000 0065 0000 0074 0000  .....l...e...t..
00000010: 0074 0000 0065 0000 0072 0000 0073 0000  .t...e...r...s..
00000020: 003a 0000 0020 0000 003c 0000 0069 0000  .:... ...<...i..
00000030: 003e 0000 fffd 0000 003c 0000 002f 0000  .>.......<.../..
00000040: 0069 0000 003e 0000                      .i...>..

与上面的例子相同.所有字母都使用32位编码.UTF-16除了使用代理对的补充字符外,只能使用16位.并且所有非ASCII字母都被编码,FFFD 0000因此丢失.

axel@arichter:~/Dokumente/JAVA/poi/poi-3.17$ xxd "./Result 10 UTF-16LE.txt" 
00000000: fdff fdff 6c00 0000 6500 0000 7400 0000  ....l...e...t...
00000010: 7400 0000 6500 0000 7200 0000 7300 0000  t...e...r...s...
00000020: 3a00 0000 2000 0000 3c00 0000 6900 0000  :... ...<...i...
00000030: 3e00 0000 fdff 0000 3c00 0000 2f00 0000  >.......<.../...
00000040: 6900 0000 3e00 0000                      i...>...

只是为了完成.与上面相同的图片.

所以结论是Ubuntu剪贴板在从Firefox复制到它之后完全搞砸了.至少对于HTML数据风格以及使用Java读取剪贴板时.

其他浏览器使用

当我使用Chromium浏览器作为数据源做同样的事情时,问题就会变小.

所以我在Chromium 打开网址https://en.wikipedia.org/wiki/Germanic_umlaut.然后我在那里选择"letters:ä"并将其复制到剪贴板中.然后我运行我的Java程序.

结果如下:

axel@arichter:~/Dokumente/JAVA/poi/poi-3.17$ xxd "./Result 1 UTF-16.txt" 
00000000: feff 003c 006d 0065 0074 0061 0020 0068  ...<.m.e.t.a. .h
...
00000800: 0061 006c 003b 0022 003e 00e4 003c 002f  .a.l.;.".>...<./
00000810: 0069 003e 0000                           .i.>..

Chromium在剪贴板中的HTML数据风格中选择了更多的HTML.但编码看起来很合适.也适用于非ASCII ä= 00E4.但是也存在一个小问题,最后还有其他字节0000不应该存在.最后UTF-16有2个额外的00字节.

axel@arichter:~/Dokumente/JAVA/poi/poi-3.17$ xxd "./Result 4 UTF-8.txt" 
00000000: 3c6d 6574 6120 6874 7470 2d65 7175 6976  ...

与上述相同.编码看起来很合适UTF-8.但是这里还有一个额外的00字节,不应该存在.

环境

DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.4 LTS"


Mozilla Firefox 61.0.1 (64-Bit)


java version "1.8.0_101"
Java(TM) SE Runtime Environment (build 1.8.0_101-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)

问题

我在代码中做错了吗?

有人可以建议如何避免剪贴板中的混乱内容?由于非ASCII字符丢失,至少从Firefox复制时,我认为我们不能修复此内容.

这是一个已知的问题吗?有人可以确认相同的行为吗?如果是这样,Firefox中是否已经有关于此的错误报告?

或者这是一个只有在Java代码读取剪贴板内容时才会出现的问题?似乎好像.因为如果我从Firefox复制内容并将其粘贴到Libreoffice Writer中,则Unicode会正确显示.如果我然后将内容从Writer复制到剪贴板并使用我的Java程序读取它,那么UTF编码是正确的,除了最后的附加00字节.因此,从Writer复制的剪贴板内容的行为类似于从Chromium浏览器复制的内容.


新的见解

字节0xFFFD似乎是Unicode字符'REPLACEMENT CHARACTER'(U + FFFD).所以这0xFDFF是这个的小端表示,并且0xEFBFBD是这个的UTF-8编码.因此,所有结果似乎都是错误解码和重新编码Unicode的结果.

似乎它的剪贴板中的内容从Firefox未来是UTF-16LEBOM永远.但后来Java得到了这个UTF-8.因此,2字节BOM成为两个混乱的字符,用0xEFBFBD替换,每个附加0x00序列成为它们自己的NUL字符,所有不正确的UTF-8字节序列的字节序列变成搞乱的字符,用0xEFBFBD替换.然后这个伪UTF-8将被重新编码.现在垃圾完成了.

例:

a?aüa具有BOM的UTF-16LE 序列将是 0xFFFE 6100 5B02 6100 FC00 6100.

这被视为UTF-8(0xEFBFBD =不是正确的UTF-8字节序列)= 0xEFBFBD 0xEFBFBD a NUL [ STX a NUL0xEFBFBD NUL a NUL.

重新编码为UTF-16LE的伪ASCII将是: 0xFDFF FDFF 6100 0000 5B00 0200 6100 0000 FDFF 0000 6100 0000

这个伪编码为UTF-8的伪ASCII将是 0xEFBF BDEF BFBD 6100 5B02 6100 EFBF BD00 6100

这正是发生的事情.

其他例子:

Â= 0x00C2 = C200UTF-16LE =伪UTF-8中的0xEFBFBD00

?= 0x80C2 = C280伪UTF-8中的UTF-16LE = 0xC280

所以我认为Firefox这不应该归咎于这个Ubuntu或者Java是运行时环境.因为从Firefox到Writer的复制/粘贴在Ubuntu中工作,我认为Java运行时环境无法正确处理Ubuntu剪贴板中的Firefox数据风格.


新见解:

我比较了flavormap.propertiesWindows 10和我的文件,Ubuntu并且有区别.在Ubuntu的本地名称text/htmlUTF8_STRING,而在WindowsHTML Format.所以我认为这可能是问题所在.所以我添加了这条线

HTML\ Format=text/html;charset=utf-8;eoln="\n";terminators=0

到我的flavormap.properties文件中Ubuntu.

之后:

Map nativesForFlavors = SystemFlavorMap.getDefaultFlavorMap().getNativesForFlavors(
   new DataFlavor[]{
   new DataFlavor("text/html;charset=UTF-16LE")
   });

System.out.println(nativesForFlavors);

版画

{java.awt.datatransfer.DataFlavor[mimetype=text/html;representatiOnclass=java.io.InputStream;charset=UTF-16LE]=HTML Format}

但是,当Java读取时,Ubuntu剪贴板内容的结果没有变化.



1> Michael Powe..:

看了这个之后,看起来这是Java的长期存在的错误(这里甚至是较旧的报告).

看起来X11 Java组件看起来希望剪贴板数据始终采用UTF-8编码,Firefox使用UTF-16编码数据.由于Java的假设,它通过强制将UTF-16解析为UTF-8来破坏文本.我试过但找不到绕过这个问题的好方法."text/html"的"text"部分似乎向Java表明从剪贴板接收的字节应始终首先解释为文本,然后以各种方式提供.我找不到任何直接从X11访问预转换字节数组的方法.


推荐阅读
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
  • Vagrant虚拟化工具的安装和使用教程
    本文介绍了Vagrant虚拟化工具的安装和使用教程。首先介绍了安装virtualBox和Vagrant的步骤。然后详细说明了Vagrant的安装和使用方法,包括如何检查安装是否成功。最后介绍了下载虚拟机镜像的步骤,以及Vagrant镜像网站的相关信息。 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
  • Tomcat安装与配置教程及常见问题解决方法
    本文介绍了Tomcat的安装与配置教程,包括jdk版本的选择、域名解析、war文件的部署和访问、常见问题的解决方法等。其中涉及到的问题包括403问题、数据库连接问题、1130错误、2003错误、Java Runtime版本不兼容问题以及502错误等。最后还提到了项目的前后端连接代码的配置。通过本文的指导,读者可以顺利完成Tomcat的安装与配置,并解决常见的问题。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了在git中如何对指定的commit id打标签,并解决了忘记打标签的问题。通过查找历史提交的commit id,可以在任意时间点打上标签。同时,还介绍了git中的一些常用命令和操作。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 本文讨论了在PHP中将空格转换为问号的问题,并提供了解决方案。文章指出,空格不是标准的空格,而是特殊的0xC2 0xA0字符。作者尝试使用mb_convert_encoding函数将utf8字符串转换为gbk编码,但未成功。文章建议检查编辑器是否对空格进行了特殊处理,并提供了使用base64_encode函数打印结果的方法。最后,给出了完整的代码示例。 ... [详细]
  • 总结一下C中string的操作,来自〈CPrimer〉第四版。1.string对象的定义和初始化:strings1;空串strings2(s1);将s2初始 ... [详细]
author-avatar
ChiuChiuLIN
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有