You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin.Forms中HTML转PDF并存储遇共享冲突问题求助

解决Xamarin.Forms中HTML转PDF的共享冲突问题

问题背景

在Xamarin.Forms中实现HTML转PDF并存储功能,先后尝试PDFSharpcore、Syncfusion.Xamarin.PDF、Xamarin.PDF等第三方库均未成功;采用Android原生WebView渲染HTML转PDF方案后,转换功能正常,但存储环节抛出**Sharing violation(共享冲突)**异常,异常路径为/storage/emulated/0/Android/data/com.bt.WasteTracker.intune/files/temp/Example_1677226869970.pdf,触发点在代码:

using (var stream = new FileStream(this.FilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))

已确认目标文件夹写入权限,且排查过文件未被其他应用/进程占用,但问题仍存在。

核心原因分析

从提供的Android原生代码来看,PdfLayoutResultCallback中通过ParcelFileDescriptor.Open打开了目标文件的读写句柄,但未确保该句柄在操作完成后及时释放;后续FileStream尝试以FileShare.None模式打开同一文件时,就会因文件句柄未释放导致共享冲突。

修复思路及步骤

1. 确保ParcelFileDescriptor及时释放

在OnLayoutFinished方法中,使用using语句包裹ParcelFileDescriptor,保证文件句柄在Adapter.OnWrite操作完成后自动释放:

public override void OnLayoutFinished(PrintDocumentInfo info, bool changed)
{
    try
    {
        var file = new Java.IO.File(PDFToHtml.FilePath);
        // 使用using自动释放文件句柄
        using (var fileDescriptor = ParcelFileDescriptor.Open(file, ParcelFileMode.ReadWrite))
        {
            var writeResultCallback = new PdfWriteResultCallback(PDFToHtml);
            Adapter.OnWrite(new PageRange[] { PageRange.AllPages }, fileDescriptor, new CancellationSignal(), writeResultCallback);
        }
    }
    catch
    {
        PDFToHtml.Status = PDFEnum.Failed;
    }

    base.OnLayoutFinished(info, changed);
}

2. 调整FileStream的共享模式

如果必须在写入操作后立即读取/操作文件,可将FileShare参数调整为FileShare.ReadWrite,允许其他进程同时读写(需确保此时文件写入已完成):

using (var stream = new FileStream(this.FilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))

3. 等待写入完成信号再操作文件

PdfWriteResultCallback的OnWriteFinished是PDF写入完成的回调,确保只有在收到该回调后,再执行FileStream相关的存储/读取操作,避免在文件写入过程中尝试打开文件:

  • 在PDFToHtml类中添加TaskCompletionSource来等待写入完成信号
  • 在OnWriteFinished中触发信号,再执行后续的文件操作

示例调整:

// 在PDFToHtml类中定义
public TaskCompletionSource<bool> WriteCompletionSource { get; } = new TaskCompletionSource<bool>();

// 在PdfWriteResultCallback的OnWriteFinished中
public override void OnWriteFinished(PageRange[] pages)
{
    base.OnWriteFinished(pages);
    pDFToHtml.Status = PDFEnum.Completed;
    pDFToHtml.WriteCompletionSource.SetResult(true);
}

// 在调用方等待写入完成后再操作文件
await pdfToHtml.WriteCompletionSource.Task;
using (var stream = new FileStream(pdfToHtml.FilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
    // 执行文件操作
}

4. 检查文件创建逻辑

确保目标文件在创建时没有被其他隐式的流占用,比如如果之前有创建文件的代码,也要用using包裹流,避免句柄泄漏:

// 示例:创建空文件时确保流释放
using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
    // 写入空内容或初始化
}

额外验证建议

  • 测试时可在触发FileStream前添加短暂延迟(仅用于排查,不建议作为最终方案),确认是否是写入未完成导致的冲突
  • 使用Android Studio的Device File Explorer查看目标文件状态,或通过lsof命令(需root权限)检查文件的占用进程

内容的提问来源于stack exchange,提问作者karanam kalyani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 00:21:26