207 lines
7.9 KiB
C#
207 lines
7.9 KiB
C#
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace KssSmaPlaLib.IO.File
|
||
{
|
||
public static class JsonFileUxer
|
||
{
|
||
/// <summary>
|
||
/// JSONファイルのピンポイント1項目更新
|
||
/// </summary>
|
||
/// <param name="path">JSONファイルパス</param>
|
||
/// <param name="jsonPath">JSONノードパス</param>
|
||
/// <param name="newValue">更新値</param>
|
||
/// <exception cref="InvalidOperationException"></exception>
|
||
// public static void UpdateJsonKeyAtomic(string path, string jsonPath, object newValue)
|
||
// {
|
||
// //// 使い方例:パスワード更新
|
||
// //JsonFiileUxer.UpdateJsonKeyAtomic("config.json", "app.auth.password", "new_pw_2026-01");
|
||
|
||
// var jtoken = JToken.FromObject(newValue);
|
||
|
||
// // 1) 読み込み(UTF-8)
|
||
// var json = System.IO.File.ReadAllText(path, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
|
||
// var jo = JObject.Parse(json);
|
||
|
||
// // 2) ピンポイント更新(途中が無ければ作る)
|
||
// var token = jo.SelectToken(jsonPath);
|
||
// if (token is null)
|
||
// {
|
||
// // 例: "app.auth.password" を分解して動的に作る
|
||
// var parts = jsonPath.Split('.');
|
||
// JToken cur = jo;
|
||
// for (int i = 0; i < parts.Length; i++)
|
||
// {
|
||
// var name = parts[i];
|
||
// var obj = cur as JObject ?? throw new InvalidOperationException("親がオブジェクトではありません");
|
||
// if (i == parts.Length - 1)
|
||
// {
|
||
// obj[name] = jtoken;
|
||
// }
|
||
// else
|
||
// {
|
||
// if (obj[name] == null) obj[name] = new JObject();
|
||
// cur = obj[name];
|
||
// }
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// token.Replace(jtoken);
|
||
// }
|
||
|
||
// // 3) 一時ファイルへ書き出し
|
||
// var dir = System.IO.Path.GetDirectoryName(path) ?? ".";
|
||
// var tmp = System.IO.Path.Combine(dir, ".tmp_config.json");
|
||
// var backup = path + $"_{DateTime.Now.ToString("yyyyMMddHHmmss")}" + ".bak";
|
||
|
||
// //var output = jo.ToString(Formatting.Indented) + Environment.NewLine;
|
||
// var output = JsonConvert.SerializeObject(jo, Formatting.Indented) + Environment.NewLine;
|
||
// System.IO.File.WriteAllText(tmp, output, new UTF8Encoding(false));
|
||
|
||
// // 4) バックアップ作成 → 原子置換
|
||
// if (System.IO.File.Exists(path)) System.IO.File.Copy(path, backup, overwrite: true);
|
||
// System.IO.File.Replace(tmp, path, backup);
|
||
// }
|
||
|
||
/// <summary>
|
||
/// JSONファイルから、jsonPathに一致する単一項目を取得します。
|
||
/// 取得に成功したら true を返し、 out value に JToken を設定します。
|
||
/// キーが見つからない・JSON無効・ファイル無し等は false を返し、 value は null。
|
||
/// </summary>
|
||
// public static bool TryGetJsonKey(string path, string jsonPath, out JToken value)
|
||
// {
|
||
// value = null;
|
||
|
||
// // 1) 読み込み(UTF-8 BOMなし)
|
||
// string json;
|
||
// try
|
||
// {
|
||
// json = System.IO.File.ReadAllText(path, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
|
||
// }
|
||
// catch (Exception)
|
||
// {
|
||
// // ファイルがない/読み取り不可
|
||
// return false;
|
||
// }
|
||
|
||
// // 2) 解析
|
||
// JObject jo;
|
||
// try
|
||
// {
|
||
// jo = JObject.Parse(json);
|
||
// }
|
||
// catch (JsonReaderException)
|
||
// {
|
||
// // JSON不正
|
||
// return false;
|
||
// }
|
||
|
||
// // 3) ピンポイント取得
|
||
// // 例: "app.auth.password" / "items[0].name" / "users['alice'].age" 等
|
||
// try
|
||
// {
|
||
// var token = jo.SelectToken(jsonPath);
|
||
// if (token is null)
|
||
// {
|
||
// return false; // キー未存在
|
||
// }
|
||
|
||
// value = token; // JValue/JObject/JArray いずれもOK
|
||
// return true;
|
||
// }
|
||
// catch (ArgumentException)
|
||
// {
|
||
// // JSONPathの書式誤り(SelectTokenが例外)
|
||
// return false;
|
||
// }
|
||
// }
|
||
|
||
/// <summary>
|
||
/// 文字列として取得(JToken型を意識したくない場合の軽量ヘルパー)。
|
||
/// </summary>
|
||
// public static bool TryGetJsonString(string path, string jsonPath, out string result)
|
||
// {
|
||
// result = string.Empty;
|
||
// if (!TryGetJsonKey(path, jsonPath, out var token)) return false;
|
||
|
||
// // JValue以外(オブジェクト/配列)の場合は ToString() を許容するか判断(ここではJValueのみ厳密)
|
||
// if (token is JValue jv)
|
||
// {
|
||
// // 文字列ならそのまま
|
||
// if (jv.Type == JTokenType.String)
|
||
// {
|
||
// result = (string)jv.Value;
|
||
// return true;
|
||
// }
|
||
|
||
// // 数値・真偽・Null などは ToString() で返す設計でもOK
|
||
// // ここでは文字列のみ厳密に true とします(お好みで分岐調整)
|
||
// return false;
|
||
// }
|
||
// return false;
|
||
// }
|
||
|
||
/// <summary>
|
||
/// 符号付き整数(Int64)で取得(intの範囲超えも想定)。
|
||
/// </summary>
|
||
// public static bool TryGetJsonInt64(string path, string jsonPath, out long result)
|
||
// {
|
||
// result = default;
|
||
// if (!TryGetJsonKey(path, jsonPath, out var token)) return false;
|
||
|
||
// if (token is JValue jv)
|
||
// {
|
||
// // JValueが数値型なら long へ
|
||
// if (jv.Type == JTokenType.Integer)
|
||
// {
|
||
// // Newtonsoftは内部的に long を持つのでキャスト可能
|
||
// try
|
||
// {
|
||
// result = Convert.ToInt64(jv.Value);
|
||
// return true;
|
||
// }
|
||
// catch
|
||
// {
|
||
// return false;
|
||
// }
|
||
// }
|
||
|
||
// // 文字列数値を許可する場合("42" → 42)
|
||
// if (jv.Type == JTokenType.String && long.TryParse((string)jv.Value, out var parsed))
|
||
// {
|
||
// result = parsed;
|
||
// return true;
|
||
// }
|
||
// }
|
||
// return false;
|
||
// }
|
||
|
||
/// <summary>
|
||
/// 任意型の既定値付き取得(存在しなければ defaultValue を返す)。
|
||
/// 例:GetJsonKeyOrDefault(path, "app.auth.retries", 3)
|
||
/// </summary>
|
||
// public static T GetJsonKeyOrDefault<T>(string path, string jsonPath, T defaultValue)
|
||
// {
|
||
// if (!TryGetJsonKey(path, jsonPath, out var token) || token is null)
|
||
// return defaultValue;
|
||
|
||
// try
|
||
// {
|
||
// // JToken → 任意型に変換(失敗時は既定値)
|
||
// var val = token.ToObject<T>();
|
||
// return val == null ? defaultValue : val;
|
||
// }
|
||
// catch
|
||
// {
|
||
// return defaultValue;
|
||
// }
|
||
// }
|
||
}
|
||
}
|