JSON.net 直接从 oledbconnection 序列化

2023-12-01

我目前有一个处理程序,它获取 Excel 文件的文件路径和选项卡名,将文件处理到数据表中,然后将表序列化为 json 字符串以返回。 这一直有效,直到我尝试处理大文件,然后出现内存不足异常。

我在想,如果我不先将所有内容加载到数据表中,而是直接加载到 json 字符串中,那么会减少内存使用量。但是,我一直无法找到任何如何执行此操作的示例。

我可以直接从 OleDbConnection 序列化为字符串吗?如何?

    public void ProcessRequest(HttpContext context)
    {
        string path = context.Request["path"];
        string tableNames = context.Request["tableNames"];

        string connectionString = string.Empty;
        if (path.EndsWith(".xls"))
        {
            connectionString = String.Format(@"Provider=Microsoft.ACE.OLEDB.12.0;
                Data Source={0};
                Extended Properties=""Excel 8.0;HDR=YES;IMEX=1""", path);
        }
        else if (path.EndsWith(".xlsx"))
        {
            connectionString = String.Format(@"Provider=Microsoft.ACE.OLEDB.12.0;
                Data Source={0};
                Extended Properties=""Excel 12.0 Xml;HDR=YES;IMEX=1""", path);
        }
        DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OleDb");

        DbDataAdapter adapter = factory.CreateDataAdapter();
        OleDbConnection conn = new OleDbConnection(connectionString);
        conn.Open();

        DataTable tmp = new DataTable();

        DbCommand selectCommand = factory.CreateCommand();

        selectCommand.CommandText = String.Format("SELECT * FROM [{0}]", tableNames);
        selectCommand.Connection = conn;
        adapter.SelectCommand = selectCommand;


        adapter.Fill(tmp);
        string tabdata = JsonConvert.SerializeObject(tmp);
        context.Response.Write(tabdata);
    }

首先,您应该停止序列化到中间string而是直接序列化到HttpResponse.OutputStream,使用以下简单方法:

public static class JsonExtensions
{
    public static void SerializeToStream(object value, System.Web.HttpResponse response, JsonSerializerSettings settings = null)
    {
        if (response == null)
            throw new ArgumentNullException("response");
        SerializeToStream(value, response.OutputStream, settings);
    }

    public static void SerializeToStream(object value, TextWriter writer, JsonSerializerSettings settings = null)
    {
        if (writer == null)
            throw new ArgumentNullException("writer");
        var serializer = JsonSerializer.CreateDefault(settings);
        serializer.Serialize(writer, value);
    }

    public static void SerializeToStream(object value, Stream stream, JsonSerializerSettings settings = null)
    {
        if (stream == null)
            throw new ArgumentNullException("stream");
        using (var writer = new StreamWriter(stream))
        {
            SerializeToStream(value, writer, settings);
        }
    }
}

由于大字符串需要大连续的底层的内存块char数组,这就是你首先会耗尽内存的地方。另请参阅 Json.NET性能技巧

为了最大限度地减少内存使用和分配的对象数量,Json.NET 支持直接序列化和反序列化到流。在处理大小大于 85kb 的 JSON 文档时,一次读取或写入一段 JSON,而不是将整个 JSON 字符串加载到内存中,这一点尤其重要,以避免 JSON 字符串最终出现在大型对象堆中。

接下来,请务必将所有一次性物品包裹在一个using语句,如下图所示。

这可能会解决您的问题,但如果没有,您可以序列化IDataReader使用以下命令转换为 JSONJsonConverter:

public class DataReaderConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(IDataReader).IsAssignableFrom(objectType);
    }

    public override bool CanRead { get { return false; } }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var reader = (IDataReader)value;
        writer.WriteStartArray();
        while (reader.Read())
        {
            writer.WriteStartObject();
            for (int i = 0; i < reader.FieldCount; i++)
            {
                writer.WritePropertyName(reader.GetName(i));
                if (reader.IsDBNull(i))
                    writer.WriteNull();
                else
                    serializer.Serialize(writer, reader[i]);
            }
            writer.WriteEndObject();
        }
        writer.WriteEndArray();
    }
}

然后序列化为stream,如下:

public static class ExcelExtensions
{
    private static string GetExcelConnectionString(string path)
    {
        string connectionString = string.Empty;
        if (path.EndsWith(".xls"))
        {
            connectionString = String.Format(@"Provider=Microsoft.ACE.OLEDB.12.0;
            Data Source={0};
            Extended Properties=""Excel 8.0;HDR=YES;IMEX=1""", path);
        }
        else if (path.EndsWith(".xlsx"))
        {
            connectionString = String.Format(@"Provider=Microsoft.ACE.OLEDB.12.0;
            Data Source={0};
            Extended Properties=""Excel 12.0 Xml;HDR=YES;IMEX=1""", path);
        }
        return connectionString;
    }

    public static string SerializeJsonToString(string path, string workSheetName, JsonSerializerSettings settings = null)
    {
        using (var writer = new StringWriter())
        {
            SerializeJsonToStream(path, workSheetName, writer, settings);
            return writer.ToString();
        }
    }

    public static void SerializeJsonToStream(string path, string workSheetName, Stream stream, JsonSerializerSettings settings = null)
    {
        using (var writer = new StreamWriter(stream))
            SerializeJsonToStream(path, workSheetName, writer, settings);
    }

    public static void SerializeJsonToStream(string path, string workSheetName, TextWriter writer, JsonSerializerSettings settings = null)
    {
        settings = settings ?? new JsonSerializerSettings();
        var converter = new DataReaderConverter();
        settings.Converters.Add(converter);
        try
        {
            string connectionString = GetExcelConnectionString(path);
            DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OleDb");

            using (OleDbConnection conn = new OleDbConnection(connectionString))
            {
                conn.Open();
                using (DbCommand selectCommand = factory.CreateCommand())
                {
                    selectCommand.CommandText = String.Format("SELECT * FROM [{0}]", workSheetName);
                    selectCommand.Connection = conn;

                    using (var reader = selectCommand.ExecuteReader())
                    {
                        JsonExtensions.SerializeToStream(reader, writer, settings);
                    }
                }
            }
        }
        finally
        {
            settings.Converters.Remove(converter);
        }
    }
}

注意-经过轻微测试。在将其投入生产之前,请务必根据现有方法对其进行单元测试!对于我使用的转换器代码DataReader 的 JSON 序列化作为灵感。

Update

我的转换器发出的 JSON 结构与DataTableConverterJson.NET 的。因此你将能够反序列化为DataTable自动使用 Json.NET。如果您喜欢更紧凑的格式,您可以定义自己的格式,例如:

{
  "columns": [
    "Name 1",
    "Name 2"
  ],
  "rows": [
    [
      "value 11",
      "value 12"
    ],
    [
      "value 21",
      "value 22"
    ]
  ]
}

他们创建了以下转换器:

public class DataReaderArrayConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(IDataReader).IsAssignableFrom(objectType);
    }

    public override bool CanRead { get { return false; } }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    static string[] GetFieldNames(IDataReader reader)
    {
        var fieldNames = new string[reader.FieldCount];
        for (int i = 0; i < reader.FieldCount; i++)
            fieldNames[i] = reader.GetName(i);
        return fieldNames;
    }

    static void ValidateFieldNames(IDataReader reader, string[] fieldNames)
    {
        if (reader.FieldCount != fieldNames.Length)
            throw new InvalidOperationException("Unequal record lengths");
        for (int i = 0; i < reader.FieldCount; i++)
            if (fieldNames[i] != reader.GetName(i))
                throw new InvalidOperationException(string.Format("Field names at index {0} differ: \"{1}\" vs \"{2}\"", i, fieldNames[i], reader.GetName(i)));
    }

    const string columnsName = "columns";
    const string rowsName = "rows";

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var reader = (IDataReader)value;
        writer.WriteStartObject();
        string[] fieldNames = null;
        while (reader.Read())
        {
            if (fieldNames == null)
            {
                writer.WritePropertyName(columnsName);
                fieldNames = GetFieldNames(reader);
                serializer.Serialize(writer, fieldNames);
                writer.WritePropertyName(rowsName);
                writer.WriteStartArray();
            }
            else
            {
                ValidateFieldNames(reader, fieldNames);
            }

            writer.WriteStartArray();
            for (int i = 0; i < reader.FieldCount; i++)
            {
                if (reader.IsDBNull(i))
                    writer.WriteNull();
                else
                    serializer.Serialize(writer, reader[i]);
            }
            writer.WriteEndArray();
        }
        if (fieldNames != null)
        {
            writer.WriteEndArray();
        }
        writer.WriteEndObject();
    }
}

当然,您需要在客户端创建自己的反序列化转换器。

或者,您可以考虑压缩您的回复。我从未尝试过,但是看看HttpWebRequest 和 GZip Http 响应 and ASP.NET GZip 编码注意事项.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JSON.net 直接从 oledbconnection 序列化 的相关文章

  • C# 方法重载决策不选择具体的泛型覆盖

    这个完整的 C 程序说明了这个问题 public abstract class Executor
  • 将类对象放置在向量中?

    我注意到我可以将一个类放置在一个向量中 这是我的程序 我收到以下错误 out blackjack exe blackjack obj blackjack obj error LNK2019 unresolved external symbo
  • 按扩展名过滤搜索文件返回太多结果

    我正在开发一个 C 控制台应用程序 它必须管理 Windows 操作系统上的文件 我需要获取具有特定扩展名的文件名 列表 我找到了很多解决方案 最建议的是以下一种 HANDLE hFind WIN32 FIND DATA data hFin
  • 如何将 SOLID 原则应用到现有项目中

    我对这个问题的主观性表示歉意 但我有点卡住了 我希望之前处理过这个问题的人能够提供一些指导和建议 我有 现在已经成为 一个用 C 2 0 编写的非常大的 RESTful API 项目 并且我的一些类已经变得巨大 我的主要 API 类就是一个
  • java中如何重新初始化int数组

    class PassingRefByVal static void Change int pArray pArray 0 888 This change affects the original element pArray new int
  • 有些有助于理解“产量”

    在我不断追求少吸的过程中 我试图理解 产量 的说法 但我不断遇到同样的错误 someMethod 的主体不能是迭代器块 因为 System Collections Generic List 不是迭代器接口类型 这是我被卡住的代码 forea
  • 如何将 .txt 文件中的数据转换为 xml? C#

    我在一个文本文件中有数千行数据 我想通过将其转换为更容易搜索的内容来轻松搜索 我希望 XML 或其他类型的大型数据结构 尽管我不确定它是否是最好的对于我的想法 每行的数据如下所示 第 31 册 托马斯 乔治 32 34 154 每本书都不是
  • 强制初始化模板类的静态数据成员

    关于模板类的静态数据成员未初始化存在一些问题 不幸的是 这些都没有能够帮助我解决我的具体问题的答案 我有一个模板类 它有一个静态数据成员 必须为特定类型显式实例化 即必须专门化 如果不是这种情况 使用不同的模板函数应该会导致链接器错误 这是
  • 不同 C++ 文件中的相同类名

    如果两个 C 文件具有相同名称的类的不同定义 那么当它们被编译和链接时 即使没有警告也会抛出一些东西 例如 a cc class Student public std string foo return A void foo a Stude
  • C++中判断unicode字符是全角还是半角

    我正在编写一个终端 控制台 应用程序 该应用程序应该包装任意 unicode 文本 终端通常使用等宽 固定宽度 字体 因此要换行文本 只需计算字符数并观察单词是否适合一行并采取相应的操作 问题是 Unicode 表中的全角字符在终端中占用了
  • 如何使用 x64 运行 cl?

    我遇到了和这里同样的问题致命错误 C1034 windows h 未设置包含路径 https stackoverflow com questions 931652 fatal error c1034 windows h no include
  • 已发布的 .Net Core 应用程序警告安装 .Net Core,但它已安装

    我制作了一个 WPF 和控制台应用程序 供某人在我无法访问的私人服务器上使用 我使用 Visual Studio 2019 的内置 发布向导 来创建依赖于框架的单文件应用程序 当该人打开 WPF 应用程序时 他们会看到标准警告 他们单击 是
  • 如何递归取消引用指针(C++03)?

    我正在尝试在 C 中递归地取消引用指针 如果传递一个对象 那就是not一个指针 这包括智能指针 我只想返回对象本身 如果可能的话通过引用返回 我有这个代码 template
  • 不可变类与结构

    以下是类与 C 中的结构的唯一区别 如果我错了 请纠正我 类变量是引用 而结构变量是值 因此在赋值和参数传递中复制结构的整个值 类变量是存储在堆栈上的指针 指向堆上的内存 而结构变量作为值存储在堆上 假设我有一个不可变的结构 该结构的字段一
  • 在 C# 中为父窗体中的子窗体控件添加事件处理程序

    我有两种形式 一种是带有按钮和文本框的父表单 单击该按钮时 将打开一个对话框 该子窗体又包含一个文本框和一个按钮 现在我想要的是 每当子表单文本框中的文本更改时 父表单文本框中的文本会自动更改 为了获得这个 我所做的是 Form3 f3 n
  • C++ - 多维数组

    处理多维数组时 是否可以为数组分配两种不同的变量类型 例如你有数组int example i j 有可能吗i and j是两种完全不同的变量类型 例如 int 和 string 听起来您正在寻找 std vector
  • 如何在 C# 中创建异步方法?

    我读过的每一篇博客文章都会告诉您如何在 C 中使用异步方法 但由于某些奇怪的原因 从未解释如何构建您自己的异步方法来使用 所以我现在有这段代码使用我的方法 private async void button1 Click object se
  • 模板类中的无效数据类型生成编译时错误?

    我正在使用 C 创建一个字符串类 我希望该类仅接受数据类型 char 和 wchar t 并且我希望编译器在编译时使用 error 捕获任何无效数据类型 我不喜欢使用assert 我怎样才能做到这一点 您可以使用静态断言 促进提供一个 ht
  • 如何解压 msgpack 文件?

    我正在将 msgpack 编码的数据写入文件 在编写时 我只是使用 C API 的 fbuffer 如 我为示例删除了所有错误处理 FILE fp fopen filename ab msgpack packer pk msgpack pa
  • EntityFramework 6.0.0.0 读取数据,但不插入

    我创建了一个基于服务的数据库 folderName gt Add New Item gt Data gt Service based Database文件到 WPF 应用程序中 然后我用过Database First方法并创建了Person

随机推荐

  • Express 中绝对路径和相对路径的困难

    我在 Express 应用程序中有一个 API 路线 如下所示 app get username bookmark function req res do stuff 正如预期的那样 该路由解析为 GET username bookmark
  • C# 列表分组并赋值

    我有一份订单清单 此列表包含同一商品的多个订单 请参阅下表 然后我想为每个相同的项目 即 ABC 分配相同的块 ID 因此 ABC 的块 ID 为 1 每个 GHJ 的块 ID 为 2 等等 最好的方法是什么 目前 我按订单 ID 对列表进
  • 从本地系统获取当前位置区域[关闭]

    Closed 这个问题需要细节或清晰度 目前不接受答案 我需要获取国家 城市 例如 America New York 从我的本地系统使用 time 包中的 LoadLocation value string 提供给 api 如何在不使用任何
  • 如何使用imageEdgeInsets更改UIButton中图像的tintColor?

    我的 Objective C 应用程序中有一个 UIButton 我的按钮经过修改 添加了文本和图像 例如 void centerButtonAndImageWithSpacing CGFloat spacing CGFloat inset
  • ISBN -> bookdata 查找填写数据库

    好的 我想为一个小型图书馆建立数据库 我对数据库的经验有限 并且没有从网络服务器查询的经验 我想要检索标题 出版商 也许是作者 描述等信息 我能想到的最简单的方法是通过 ISBN 查找它们 我以前接触过 isbndb com 但访问它的 A
  • 为什么是行家?有什么好处? [关闭]

    Closed 这个问题是基于意见的 目前不接受答案 与 ant 相比 使用 Maven 的主要好处是什么 它似乎更像是一种烦恼 而不是一个有用的工具 我使用 maven 2 普通 Eclipse Java EE 无 m2eclipse 和
  • ClickOnce 应用程序安装 - 安全警告

    我有一个部署在网站上的 clickonce 应用程序 例如 http example com 用户将从该网站下载我发布的应用程序的 setup exe 文件 并将该应用程序安装在他们的计算机上 我已使用 GoDaddy 为我公司颁发的证书签
  • aws beanstalk nodejs:如何覆盖 nginx 的 60 秒超时

    我想增加AWS弹性beanstalk中nodejs环境中nginx的默认超时 我正在遵循本指南 https medium com swlh using ebextensions to extend nginx default configu
  • 控制R中ggplot2中多个geom_line的颜色

    我想绘制 3 条回归线 一条对应 tau 的每个值 每条都有其颜色 如数据集中指定的那样 互联网上说您在一般情节美学中提供了颜色变量 http ggplot yhathq com docs geom line html 但这似乎不起作用 任
  • IServiceCollection 不包含 AddAzureClients 的定义

    我正在尝试添加 blob 服务客户端以进行依赖项注入 我正在使用最新版本Microsoft Extensions Azure 但是我的服务集合不包含扩展方法AddAzureClients 服务集合的类型为Microsoft Extensio
  • 库存数量宏 excel

    我正在尝试让 Excel 作为库存扫描阅读器 我在扫描时遇到问题 因为当我扫描时它会不断添加到列 A 即使它是重复的 我希望它能够识别扫描的项目与上次相同并添加到列数量 如果有人可以帮助我如何编写代码 那就太好了 图片 它不让我放一张 但
  • 从另一个页面获取ElementById

    我正在尝试获得一个div从一个网页 URL 到另一个网页并使用纯文本显示getElementById不使用 AJAX 或 jQuery 因为我将在 FitNesse 中实现它 有没有办法传递URL 您可以在隐藏的 iframe 中加载 UR
  • 获取嵌套 html 标签内的字符偏移量

    我有类似于此的 HTML 代码 pre words words words words span words mystery words span words words words pre 我想获得 神秘 相对于的字符偏移量pre使用 J
  • 在 Winforms 中从外部线程访问 UI

    在 WPF 中 可以使用类似以下内容 Application Current Dispatcher BeginInvoke new Action gt Form1 grid Items Refresh 访问主线程之外的 UI 功能 然而 在
  • 从datagridview复制粘贴到excel时如何保留颜色?

    我使用以下 CellFormatting 代码有条件地为 datagridview 中的行着色 private void SGridView CellFormatting object sender DataGridViewCellForm
  • TimeZoneInfo.GetSystemTimeZones() 如何仅选择特定国家/地区代码的条目?

    TimeZoneInfo GetSystemTimeZones 为您提供所有时区的枚举 问题是如何仅选择特定国家 地区代码的条目 我知道 UTC 偏移量和国家 地区代码 并且需要能够选择正确的时区值 首先 您会发现由于夏令时的变化 可能还有
  • Java Swing Combobox removeAllItems 还调用 ItemStateChanged 吗?

    我的代码实际上很简单 我看到一个简单且相似的代码来自本文 首先 我有 1 个组合框 我有一个听众叫itemStateChanged 我添加到这个监听器中的目的是 当用户从其保管箱中单击 选择 一个项目时执行一些代码 Cmb ItemCate
  • 毕加索本地图片加载速度慢?

    我开发 Android 应用程序已有六年了 并且使用简单的 自制 图像缓存库也有同样长的时间 我最近开始使用一个依赖于 Picasso 的组件 并决定可能是时候切换到通用库了 而不是保留我多年前编写的旧解决方案 我的大多数图像都是存储在可绘
  • 如何在本地机器上使用带有 sdk 的云构建来构建 docker 镜像,而无需尝试它

    我在用着云构建构建 docker 镜像 从以下位置提供的示例中指导自己github 垃圾桶 包装 源代码 cloud google com contrib go opencensus io github com go opencensus
  • JSON.net 直接从 oledbconnection 序列化

    我目前有一个处理程序 它获取 Excel 文件的文件路径和选项卡名 将文件处理到数据表中 然后将表序列化为 json 字符串以返回 这一直有效 直到我尝试处理大文件 然后出现内存不足异常 我在想 如果我不先将所有内容加载到数据表中 而是直接