for Push.

This commit is contained in:
nobobo
2026-06-01 13:23:34 +09:00
parent 9e093ea99f
commit a6550e9928
93 changed files with 10393 additions and 0 deletions
+206
View File
@@ -0,0 +1,206 @@
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 = null;
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;
}
}
}
}