Mac下.rtf文件中String转化Int失败

本文介绍了一个使用Apache Spark处理RTF文件时遇到的问题,由于文件格式导致无法正确转换为整数,从而引发NumberFormatException异常。文章提供了详细的错误信息,并提出了解决方案:使用纯文本文件代替RTF文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:在macOS下进行spark作业:输出文件中最大及最小数

文件结构如下:

代码如下:

import org.apache.spark.{SparkConf, SparkContext}

object MaxAndMin {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local").setAppName("MaxAndMin")
    val sc = new SparkContext(sparkConf)
    sc.setLogLevel("ERROR")

    val lines = sc.textFile("hdfs://localhost:9000/b.txt")//此处为b.rtf时报错
    val result = lines.filter(_.trim.length>0).
      map(line => ("key",line.trim.toInt)).//此处报错
      groupByKey().
      map(x => {
        var max = Integer.MIN_VALUE
        var min = Integer.MAX_VALUE
        for(num <- x._2) {
          if(num > max)
            max = num
          if(num < min)
            min = num
        }
        (max,min)
      }).collect.foreach(x => {
      println("max:\t" + x._1)
      println("min:\t" + x._2)
    })

  }
}

异常信息:

ERROR Executor: Exception in task 0.0 in stage 0.0 (TID 0)
java.lang.NumberFormatException: For input string: "{\rtf1\ansi\ansicpg936\cocoartf1561\cocoasubrtf400"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:580)
	at java.lang.Integer.parseInt(Integer.java:615)
	at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272)
	at scala.collection.immutable.StringOps.toInt(StringOps.scala:29)
	at MaxAndMin$$anonfun$2.apply(MaxAndMin.scala:11)
	at MaxAndMin$$anonfun$2.apply(MaxAndMin.scala:11)
	at scala.collection.Iterator$$anon$11.next(Iterator.scala:409)
	at org.apache.spark.shuffle.sort.BypassMergeSortShuffleWriter.write(BypassMergeSortShuffleWriter.java:150)
	at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:96)
	at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:53)
	at org.apache.spark.scheduler.Task.run(Task.scala:99)
	at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:282)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
18/06/23 22:27:48 ERROR TaskSetManager: Task 0 in stage 0.0 failed 1 times; aborting job
Exception in thread "main" org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 0.0 failed 1 times, most recent failure: Lost task 0.0 in stage 0.0 (TID 0, localhost, executor driver): java.lang.NumberFormatException: For input string: "{\rtf1\ansi\ansicpg936\cocoartf1561\cocoasubrtf400"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:580)
	at java.lang.Integer.parseInt(Integer.java:615)
	at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272)
	at scala.collection.immutable.StringOps.toInt(StringOps.scala:29)
	at MaxAndMin$$anonfun$2.apply(MaxAndMin.scala:11)
	at MaxAndMin$$anonfun$2.apply(MaxAndMin.scala:11)
	at scala.collection.Iterator$$anon$11.next(Iterator.scala:409)
	at org.apache.spark.shuffle.sort.BypassMergeSortShuffleWriter.write(BypassMergeSortShuffleWriter.java:150)
	at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:96)
	at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:53)
	at org.apache.spark.scheduler.Task.run(Task.scala:99)
	at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:282)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

Driver stacktrace:
	at org.apache.spark.scheduler.DAGScheduler.org$apache$spark$scheduler$DAGScheduler$$failJobAndIndependentStages(DAGScheduler.scala:1435)
	at org.apache.spark.scheduler.DAGScheduler$$anonfun$abortStage$1.apply(DAGScheduler.scala:1423)
	at org.apache.spark.scheduler.DAGScheduler$$anonfun$abortStage$1.apply(DAGScheduler.scala:1422)
	at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
	at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
	at org.apache.spark.scheduler.DAGScheduler.abortStage(DAGScheduler.scala:1422)
	at org.apache.spark.scheduler.DAGScheduler$$anonfun$handleTaskSetFailed$1.apply(DAGScheduler.scala:802)
	at org.apache.spark.scheduler.DAGScheduler$$anonfun$handleTaskSetFailed$1.apply(DAGScheduler.scala:802)
	at scala.Option.foreach(Option.scala:257)
	at org.apache.spark.scheduler.DAGScheduler.handleTaskSetFailed(DAGScheduler.scala:802)
	at org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.doOnReceive(DAGScheduler.scala:1650)
	at org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.onReceive(DAGScheduler.scala:1605)
	at org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.onReceive(DAGScheduler.scala:1594)
	at org.apache.spark.util.EventLoop$$anon$1.run(EventLoop.scala:48)
	at org.apache.spark.scheduler.DAGScheduler.runJob(DAGScheduler.scala:628)
	at org.apache.spark.SparkContext.runJob(SparkContext.scala:1918)
	at org.apache.spark.SparkContext.runJob(SparkContext.scala:1931)
	at org.apache.spark.SparkContext.runJob(SparkContext.scala:1944)
	at org.apache.spark.SparkContext.runJob(SparkContext.scala:1958)
	at org.apache.spark.rdd.RDD$$anonfun$collect$1.apply(RDD.scala:935)
	at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:151)
	at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:112)
	at org.apache.spark.rdd.RDD.withScope(RDD.scala:362)
	at org.apache.spark.rdd.RDD.collect(RDD.scala:934)
	at MaxAndMin$.main(MaxAndMin.scala:23)
	at MaxAndMin.main(MaxAndMin.scala)
Caused by: java.lang.NumberFormatException: For input string: "{\rtf1\ansi\ansicpg936\cocoartf1561\cocoasubrtf400"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:580)
	at java.lang.Integer.parseInt(Integer.java:615)
	at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272)
	at scala.collection.immutable.StringOps.toInt(StringOps.scala:29)
	at MaxAndMin$$anonfun$2.apply(MaxAndMin.scala:11)
	at MaxAndMin$$anonfun$2.apply(MaxAndMin.scala:11)
	at scala.collection.Iterator$$anon$11.next(Iterator.scala:409)
	at org.apache.spark.shuffle.sort.BypassMergeSortShuffleWriter.write(BypassMergeSortShuffleWriter.java:150)
	at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:96)
	at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:53)
	at org.apache.spark.scheduler.Task.run(Task.scala:99)
	at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:282)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
可以看到,第十一行的

map(line => ("key",line.trim.toInt))

类型转换异常,在什么时候会抛这个异常呢?

在“abc”.toInt时会出现此异常,原因是.rtf文件不是一个纯文本格式,.trim()方法消除空格后还存在一些奇怪的东西,所以.toInt会抛异常。

解决方法:用txt格式文件作为源文件。

在macOS下编辑txt:点击打开链接

<think>嗯,用户问的是如何在Spring接口中实现读取RTF文件中的图片信息。首先,我需要回忆一下RTF文件的结构。RTF文件虽然看起来是富文本格式,但实际上是一种包含各种控制符号和数据的文本文件。图片在RTF中通常以二进制形式嵌入,比如使用像{\pict...}这样的标签,后面跟着可能是十六进制或二进制编码的图像数据。 接下来,用户可能需要在Spring Boot应用中创建一个REST接口,接收上传的RTF文件,然后解析出其中的图片。那么,我需要考虑如何解析RTF文件的结构,提取图片数据,并将其转换为可用的格式,比如字节数组或者保存为文件。 首先,处理上传文件的话,可以使用Spring的MultipartFile来接收上传的文件。然后,读取RTF文件的内容,可能需要按行读取或者整个读取。接下来,解析RTF中的图片部分。这里的关键是识别RTF中的图片对象,通常以{\pict开头,然后是图片的元数据,比如格式、尺寸,接着是二进制数据。但RTF中的图片数据可能以十六进制字符串形式存在,比如PNG图片可能用\pngblip标识,后面跟着十六进制数据。 所以,解析步骤大致是:读取RTF文件内容,使用正则表达式或字符串查找定位{\pict部分,提取其中的图片数据。然后,将十六进制字符串转换为字节数组。需要注意的是,图片数据可能跨越多行,或者在控制符号中有其他参数,需要正确截取数据部分。 例如,RTF中的图片部分可能类似于: {\pict\pngblip\picw1000\pich800 ... 424D3E000000... } 这里的...代表十六进制数据。需要提取从pngblip之后的十六进制字符串,并将其转换为字节数组。但要注意,可能中间有其他参数,比如picw和pich,需要跳过这些参数,直到找到真正的数据部分。 然后,处理这些数据时,需要将十六进制字符串转换为字节。比如,字符串"424D"对应字节0x42和0x4D,即'B'和'M',这是BMP文件的标志。但如果是PNG,则可能以PNG头开始。因此,转换后的字节数组可以写入文件或作为响应返回。 另外,可能需要处理多个图片的情况,所以在解析时,要循环查找所有匹配的{\pict块。 可能的挑战包括正确解析RTF的结构,处理转义字符,以及处理不同图片格式的数据。此外,RTF可能有不同的编码方式,比如有的图片数据可能用二进制格式,需要不同的解码方式。 在代码实现上,可能需要用IOUtils读取MultipartFile的内容,然后用正则表达式匹配{\pict.*?}(非贪婪匹配),但需要注意大括号嵌套的问题,不过RTF中的图片块通常是独立的。或者逐行扫描,当遇到{\pict时开始记录,直到遇到}为止。 然后,提取出图片数据部分,分割参数,找到数据部分。比如,数据部分可能在最后一个参数之后,以空格分隔,或者以特定的控制字结束。例如,对于\pngblip后面的数据,可能直接跟随十六进制字符串,直到闭合的}。 将十六进制字符串转换为字节数组时,可以使用DatatypeConverter.parseHexBinary,但需要注意Java 8之后可能移除了这个类,可以使用其他方式,比如Apache Commons Codec的Hex类,或者自己编写转换方法。 最后,将提取的字节数组保存为文件,或者作为HTTP响应返回,比如用Base64编码后返回URL或直接作为文件下载。 可能的错误处理包括处理没有图片的情况,或者无效的RTF文件,这时候需要返回适当的错误信息。 综上,实现步骤大致是: 1. 创建Spring REST接口接收MultipartFile。 2. 读取RTF文件内容为字符串。 3. 使用正则表达式或字符串处理提取所有图片块。 4. 解析每个图片块的元数据和数据部分。 5. 将十六进制数据转换为字节数组。 6. 保存或返回图片数据。 在代码示例中,需要注意处理多张图片,比如返回列表。此外,不同的图片类型可能需要不同的处理,比如PNG、JPEG、BMP等,根据元数据中的控制字判断类型。 可能的问题包括:RTF文件中的图片数据是否总是以十六进制形式存在?有没有其他编码方式?例如,某些RTF生成器可能使用二进制嵌入,可能需要不同的解析方法。但大多数情况下,图片数据以十六进制存储,用\hex标识。 另一个问题是,图片数据可能被分割成多个部分,或者包含转义字符,比如\’这样的转义,这时候需要处理转义字符,还原正确的十六进制数据。 因此,在解析过程中,可能需要替换掉RTF中的转义字符,比如将\'替换为单引号,但这可能影响数据部分,需要确认图片数据是否会被转义。这部分可能需要更详细的RTF规范了解。 不过对于简单的实现,可能假设图片数据部分没有转义字符,直接提取十六进制字符串进行转换。 综上,给出一个示例代码,使用正则表达式匹配图片块,提取数据,转换为字节数组,并返回图片列表。需要处理可能的异常,比如无效的数据格式,或者没有图片的情况。</think>在Spring中读取RTF文件中的图片信息需要通过解析RTF文件格式并提取二进制图像数据。以下是具体实现步骤和代码示例: --- ### 实现步骤 1. **接收RTF文件上传**:使用Spring的`MultipartFile`接收上传文件 2. **读取RTF内容**:将文件内容转换为字符串格式 3. **解析图片数据块**:通过正则表达式匹配RTF中的`\pict`标记 4. **提取十六进制数据**:从匹配的块中分离出图像二进制数据 5. **转换为字节数组**:将十六进制字符串转换为可用的图像字节数据 --- ### 示例代码 ```java @RestController public class RtfImageController { @PostMapping("/extract-images") public ResponseEntity<List<byte[]>> extractImages(@RequestParam("file") MultipartFile file) throws IOException { String rtfContent = new String(file.getBytes(), StandardCharsets.UTF_8); List<byte[]> images = parseRtfForImages(rtfContent); return ResponseEntity.ok(images); } private List<byte[]> parseRtfForImages(String rtfContent) { List<byte[]> images = new ArrayList<>(); Pattern pattern = Pattern.compile("\\\\pict.*?\\\\(pngblip|jpegblip|dibitmap).*?([0-9a-fA-F]+)"); Matcher matcher = pattern.matcher(rtfContent); while (matcher.find()) { String hexData = matcher.group(2); byte[] imageBytes = hexStringToByteArray(hexData); if (imageBytes.length > 0) { images.add(imageBytes); } } return images; } private byte[] hexStringToByteArray(String hex) { hex = hex.replaceAll("\\s+", ""); // 移除空格 int len = hex.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); } return data; } } ``` --- ### 原理解释 1. **RTF文件结构**:RTF使用`{\pict`标记表示图片段落,包含格式标识(如`pngblip`)和HEX编码的二进制数据 2. **正则表达式解析**:`\\\\pict.*?\\\\(pngblip|jpegblip).*?([0-9a-fA-F]+)`匹配: - `\\pict`:图片段开始标记 - `(pngblip|jpegblip)`:图片格式标识 - `([0-9a-fA-F]+)`:捕获HEX数据 3. **HEX转换**:将连续HEX字符两两组合转换为字节 --- ### 注意事项 1. **编码验证**:某些RTF文件可能使用压缩格式(如`\bin`标记),需额外处理二进制数据 2. **多图片处理**:RTF可能包含多个`\pict`段,需遍历所有匹配结果 3. **错误处理**:需要添加对无效HEX数据的容错机制 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值