使用 NSData 块对文件进行 Base64 编码
更新4
根据 Greg 的建议,我创建了一对图像/文本,显示使用 100k 块从 37k 图像到 Base64 编码的输出。由于文件只有 37k,因此可以肯定地说循环仅迭代一次,因此没有附加任何内容。另一对显示使用 10k 块从相同 37k 图像到 Base64 编码的输出。由于文件大小为 37k,因此循环迭代了四次,并且数据肯定已附加。
对两个文件进行比较表明,在 10kb 块文件上,从第 214 行开始到第 640 行结束,存在很大差异。
- 小图像 (37k) - 100k 块 - 图像输出
- 小图像 (37k) - 100k 块- Base64 文本输出
- 小图像 (37k) - 10k 块 - 图像输出
- < a href="http://pastebin.com/8srAhXxf" rel="nofollow noreferrer">小图像 (37k) - 10k 块 - Base64 文本输出
更新 3
这是我的代码现在所在的位置。进行了一些清理,但仍然产生相同的效果:
// Read data in chunks from the original file [originalFile seekToEndOfFile]; NSUInteger fileLength = [originalFile offsetInFile]; [originalFile seekToFileOffset:0]; NSUInteger chunkSize = 100 * 1024; NSUInteger offset = 0; while(offset < fileLength) { NSData *chunk = [originalFile readDataOfLength:chunkSize]; offset += chunkSize; // Convert the chunk to a base64 encoded string and back into NSData NSString *base64EncodedChunkString = [chunk base64EncodedString]; NSData *base64EncodedChunk = [base64EncodedChunkString dataUsingEncoding:NSASCIIStringEncoding]; // Write the encoded chunk to our output file [encodedFile writeData:base64EncodedChunk]; // Cleanup base64EncodedChunkString = nil; base64EncodedChunk = nil; // Update progress bar [self updateProgress:[NSNumber numberWithInt:offset] total:[NSNumber numberWithInt:fileLength]]; }
更新 2
因此,看起来大于 100 KB 的文件会被扰乱,但小于 100 KB 的文件却没问题。很明显,我的缓冲区/数学/等等出了问题,但我迷失了这一点。也许是时候到此为止了,但我很想在解决这个问题后入睡。
下面是一个示例:
更新 1< br> 经过一些测试后,我发现相同的代码对于小图像可以正常工作,但对于任何尺寸的大图像或视频都不起作用。看起来肯定是缓冲区问题,对吧?
嘿,尝试通过循环并一次处理一小块来对大文件进行 Base64 编码。一切似乎都正常,但文件最终总是被损坏。我很好奇是否有人能指出我在这里可能出错的地方:
NSFileHandle *originalFile, *encodedFile; self.localEncodedURL = [NSString stringWithFormat:@"%@-base64.xml", self.localURL]; // Open the original file for reading originalFile = [NSFileHandle fileHandleForReadingAtPath:self.localURL]; if (originalFile == nil) { [self performSelectorOnMainThread:@selector(updateStatus:) withObject:@"Encoding failed." waitUntilDone:NO]; return; } encodedFile = [NSFileHandle fileHandleForWritingAtPath:self.localEncodedURL]; if (encodedFile == nil) { [self performSelectorOnMainThread:@selector(updateStatus:) withObject:@"Encoding failed." waitUntilDone:NO]; return; } // Read data in chunks from the original file [originalFile seekToEndOfFile]; NSUInteger length = [originalFile offsetInFile]; [originalFile seekToFileOffset:0]; NSUInteger chunkSize = 100 * 1024; NSUInteger offset = 0; do { NSUInteger thisChunkSize = length - offset > chunkSize ? chunkSize : length - offset; NSData *chunk = [originalFile readDataOfLength:thisChunkSize]; offset += [chunk length]; NSString *base64EncodedChunkString = [chunk base64EncodedString]; NSData *base64EncodedChunk = [base64EncodedChunkString dataUsingEncoding:NSASCIIStringEncoding]; [encodedFile writeData:base64EncodedChunk]; base64EncodedChunkString = nil; base64EncodedChunk = nil; } while (offset < length);
Update 4
Per Greg's suggestion I've created one pair of image/text that shows the output from a 37k image to base64 encoded, using 100k chunks. Since the file is only 37k it's safe to say the loop only iterated once, so nothing was appended. The other pair shows the output from the same 37k image to base64 encoded, using 10k chunks. Since the file is 37k the loop iterated four times, and data was definitely appended.
Doing a diff on the two files shows that on the 10kb chunk file there's a large difference that begins on line 214 and ends on line 640.
- Small Image (37k) - 100k Chunks - Image output
- Small Image (37k) - 100k Chunks - Base64 Text output
- Small Image (37k) - 10k Chunks - Image output
- Small Image (37k) - 10k Chunks - Base64 Text output
Update 3
Here's where my code is now. Cleaned up a bit but still producing the same effect:
// Read data in chunks from the original file [originalFile seekToEndOfFile]; NSUInteger fileLength = [originalFile offsetInFile]; [originalFile seekToFileOffset:0]; NSUInteger chunkSize = 100 * 1024; NSUInteger offset = 0; while(offset < fileLength) { NSData *chunk = [originalFile readDataOfLength:chunkSize]; offset += chunkSize; // Convert the chunk to a base64 encoded string and back into NSData NSString *base64EncodedChunkString = [chunk base64EncodedString]; NSData *base64EncodedChunk = [base64EncodedChunkString dataUsingEncoding:NSASCIIStringEncoding]; // Write the encoded chunk to our output file [encodedFile writeData:base64EncodedChunk]; // Cleanup base64EncodedChunkString = nil; base64EncodedChunk = nil; // Update progress bar [self updateProgress:[NSNumber numberWithInt:offset] total:[NSNumber numberWithInt:fileLength]]; }
Update 2
So it looks like files that are larger than 100 KB get scrambled, but files under 100 KB are fine. It's obvious that something is off on my buffer/math/etc, but I'm lost on this one. Might be time to call it a day, but I'd love to go to sleep with this one resolved.
Here's an example:
Update 1
After doing some testing I have found that the same code will work fine for a small image, but will not work for a large image or video of any size. Definitely looks like a buffer issue, right?
Hey there, trying to base64 encode a large file by looping through and doing it one small chunk at a time. Everything seems to work but the files always end up corrupted. I was curious if anyone could point out where I might be going wrong here:
NSFileHandle *originalFile, *encodedFile; self.localEncodedURL = [NSString stringWithFormat:@"%@-base64.xml", self.localURL]; // Open the original file for reading originalFile = [NSFileHandle fileHandleForReadingAtPath:self.localURL]; if (originalFile == nil) { [self performSelectorOnMainThread:@selector(updateStatus:) withObject:@"Encoding failed." waitUntilDone:NO]; return; } encodedFile = [NSFileHandle fileHandleForWritingAtPath:self.localEncodedURL]; if (encodedFile == nil) { [self performSelectorOnMainThread:@selector(updateStatus:) withObject:@"Encoding failed." waitUntilDone:NO]; return; } // Read data in chunks from the original file [originalFile seekToEndOfFile]; NSUInteger length = [originalFile offsetInFile]; [originalFile seekToFileOffset:0]; NSUInteger chunkSize = 100 * 1024; NSUInteger offset = 0; do { NSUInteger thisChunkSize = length - offset > chunkSize ? chunkSize : length - offset; NSData *chunk = [originalFile readDataOfLength:thisChunkSize]; offset += [chunk length]; NSString *base64EncodedChunkString = [chunk base64EncodedString]; NSData *base64EncodedChunk = [base64EncodedChunkString dataUsingEncoding:NSASCIIStringEncoding]; [encodedFile writeData:base64EncodedChunk]; base64EncodedChunkString = nil; base64EncodedChunk = nil; } while (offset < length);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我希望我能把功劳归功于 GregInYEG,因为他关于填充的最初观点是根本问题。使用 Base64,每个块必须是 3 的倍数。所以这解决了问题:
一旦我有了这个,损坏就消失了。但后来我遇到了内存泄漏问题,所以我添加了从这篇文章中获取的自动释放池方法: http://www.cocoadev.com/index.pl?ReadAFilePieceByPiece
最终代码:
I wish I could give credit to GregInYEG, because his original point about padding was the underlying issue. With base64, each chunk has to be a multiple of 3. So this resolved the issue:
Once I had that, the corruption went away. But then I ran into memory leak issues, so I added the autorelease pool apprach taken from this post: http://www.cocoadev.com/index.pl?ReadAFilePieceByPiece
Final code:
如何将 Base64 数据转换回图像?某些实现会限制它们可接受的最大行长度。尝试每隔多个字符插入一个换行符。
How are you converting back the base64 data to an image? Some implementations limit the maximum line length they will accept. Try inserting a line break every so many characters.