for Push.
This commit is contained in:
+484
@@ -0,0 +1,484 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from `dotnet new gitignore`
|
||||||
|
|
||||||
|
# dotenv files
|
||||||
|
.env
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# Tye
|
||||||
|
.tye/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.tlog
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||||
|
*.vbp
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||||
|
*.dsw
|
||||||
|
*.dsp
|
||||||
|
|
||||||
|
# Visual Studio 6 technical files
|
||||||
|
*.ncb
|
||||||
|
*.aps
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# Visual Studio History (VSHistory) files
|
||||||
|
.vshistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# VS Code files for those working on multiple tools
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
*.sln.iml
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
##
|
||||||
|
## Visual studio for Mac
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
# globs
|
||||||
|
Makefile.in
|
||||||
|
*.userprefs
|
||||||
|
*.usertasks
|
||||||
|
config.make
|
||||||
|
config.status
|
||||||
|
aclocal.m4
|
||||||
|
install-sh
|
||||||
|
autom4te.cache/
|
||||||
|
*.tar.gz
|
||||||
|
tarballs/
|
||||||
|
test-results/
|
||||||
|
|
||||||
|
# Mac bundle stuff
|
||||||
|
*.dmg
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# content below from: https://github.com/github/gitignore/blob/main/Global/macOS.gitignore
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# content below from: https://github.com/github/gitignore/blob/main/Global/Windows.gitignore
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
# Vim temporary swap files
|
||||||
|
*.swp
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Commons.Conversion
|
||||||
|
{
|
||||||
|
public static class KanaConvertUxer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 半角カタカナを全角カタカナに変換します。
|
||||||
|
/// 空文字やnullはそのまま返却します。
|
||||||
|
/// </summary>
|
||||||
|
// public static bool TryConvertHankakuToZenkaku(string input, out string result, out string resultMessage)
|
||||||
|
// {
|
||||||
|
// result = input;
|
||||||
|
// resultMessage = string.Empty;
|
||||||
|
|
||||||
|
// if (string.IsNullOrEmpty(input))
|
||||||
|
// return true;
|
||||||
|
|
||||||
|
// // 半角カタカナが含まれているかチェック
|
||||||
|
// if (!Regex.IsMatch(input, @"[\uFF61-\uFF9F]"))
|
||||||
|
// return true;
|
||||||
|
|
||||||
|
// // 変換処理
|
||||||
|
// result = Microsoft.VisualBasic.Strings.StrConv(input, Microsoft.VisualBasic.VbStrConv.Katakana | Microsoft.VisualBasic.VbStrConv.Wide, 0);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 全角カタカナを半角カタカナに変換します。
|
||||||
|
/// 空文字やnullはそのまま返却します。
|
||||||
|
/// </summary>
|
||||||
|
// public static bool TryConvertZenkakuToHankaku(string input, out string result, out string resultMessage)
|
||||||
|
// {
|
||||||
|
// result = input;
|
||||||
|
// resultMessage = string.Empty;
|
||||||
|
|
||||||
|
// if (string.IsNullOrEmpty(input))
|
||||||
|
// return true;
|
||||||
|
|
||||||
|
// // 全角カタカナが含まれているかチェック(ざっくり)
|
||||||
|
// if (!Regex.IsMatch(input, @"[\u30A0-\u30FF]"))
|
||||||
|
// return true;
|
||||||
|
|
||||||
|
// // 変換処理
|
||||||
|
// result = Microsoft.VisualBasic.Strings.StrConv(input, Microsoft.VisualBasic.VbStrConv.Katakana | Microsoft.VisualBasic.VbStrConv.Narrow, 0);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Commons
|
||||||
|
{
|
||||||
|
public static class DateHelperUxer
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指定した年と月の末日を返します。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="year">年(例: 2025)</param>
|
||||||
|
/// <param name="month">月(1~12)</param>
|
||||||
|
/// <returns>末日(28~31)</returns>
|
||||||
|
public static bool TryGetLastDayOfMonth(int year, int month, out int matsubi,out string resultMessage)
|
||||||
|
{
|
||||||
|
matsubi = -1;
|
||||||
|
resultMessage = string.Empty;
|
||||||
|
|
||||||
|
if (month < 1 || month > 12)
|
||||||
|
{
|
||||||
|
resultMessage = "月が1~12の範囲ではありません。";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DateTime構造体を使って末日を取得
|
||||||
|
matsubi = DateTime.DaysInMonth(year, month);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using KssSmaPlaLib.IO.File;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Commons
|
||||||
|
{
|
||||||
|
public static class DictionaryUxer
|
||||||
|
{
|
||||||
|
// /// <summary>
|
||||||
|
// /// 指定されたキーに対応する値(string)を取得します。キーが存在しない場合は 指定されたデフォルト値(未指定時はnull) を返します。
|
||||||
|
// /// </summary>
|
||||||
|
// public static TValue GetValueOrDefault<TKey, TValue>(
|
||||||
|
// Dictionary<TKey, TValue> dict,
|
||||||
|
// TKey key,
|
||||||
|
// TValue defaultValue = default)
|
||||||
|
// {
|
||||||
|
// return dict.TryGetValue(key, out TValue value) ? value : defaultValue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static bool CreateNameToIdDic(string pcsv, out Dictionary<string,int> dic, out string resultMessage)
|
||||||
|
{
|
||||||
|
resultMessage = string.Empty;
|
||||||
|
dic = new Dictionary<string,int>();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(pcsv)) return true;
|
||||||
|
|
||||||
|
var csvArray = pcsv.Split('|');
|
||||||
|
foreach (var csv in csvArray)
|
||||||
|
{
|
||||||
|
var items = csv.Split(',');
|
||||||
|
if (items.Length != 2)
|
||||||
|
{
|
||||||
|
resultMessage = $"要素数が{items.Length}個のCSVあり[CSV:{csv}]";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDの数値チェック
|
||||||
|
if (!int.TryParse(items[1], out int id))
|
||||||
|
{
|
||||||
|
resultMessage = $"IDが数値でないCSVあり[CSV:{csv}]";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nameのカンマ記号復元
|
||||||
|
items[0] = items[0].Replace("@@@COMMA@@@", ",");
|
||||||
|
|
||||||
|
dic[items[0]] = id;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Commons
|
||||||
|
{
|
||||||
|
public class EncodingUxer
|
||||||
|
{
|
||||||
|
#region 列挙体
|
||||||
|
|
||||||
|
public enum EncodingType
|
||||||
|
{
|
||||||
|
Utf8WithBom,
|
||||||
|
Utf8WithoutBom,
|
||||||
|
ShiftJIS
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public static Encoding GetEncoding(EncodingType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case EncodingType.Utf8WithBom:
|
||||||
|
return new UTF8Encoding(encoderShouldEmitUTF8Identifier: true); // BOMあり
|
||||||
|
case EncodingType.Utf8WithoutBom:
|
||||||
|
return new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); // BOMなし
|
||||||
|
case EncodingType.ShiftJIS:
|
||||||
|
return Encoding.GetEncoding("shift_jis"); // ANSI(Windows-932)
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(type), "未対応のエンコーディングです");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EncodingType? GetEncodingType(string typeString)
|
||||||
|
{
|
||||||
|
typeString = typeString.ToLower();
|
||||||
|
|
||||||
|
if (StringUxer.WildcardMatch(typeString, "*utf*8*without*bom*"))
|
||||||
|
return EncodingType.Utf8WithoutBom;
|
||||||
|
if (StringUxer.WildcardMatch(typeString, "*utf*8*with*bom*"))
|
||||||
|
return EncodingType.Utf8WithBom;
|
||||||
|
if (StringUxer.WildcardMatch(typeString, "*utf*8*"))
|
||||||
|
return EncodingType.Utf8WithoutBom;
|
||||||
|
if (StringUxer.WildcardMatch(typeString, "*s*jis*"))
|
||||||
|
return EncodingType.ShiftJIS;
|
||||||
|
if (StringUxer.WildcardMatch(typeString, "*シ*jis*"))
|
||||||
|
return EncodingType.ShiftJIS;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Commons
|
||||||
|
{
|
||||||
|
public static class IntUxer
|
||||||
|
{
|
||||||
|
public static int StrToInt(string str, int defaultValue)
|
||||||
|
{
|
||||||
|
if (int.TryParse(str, out int intValue))
|
||||||
|
{
|
||||||
|
return intValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
using KssSmaPlaLib.Ini;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Events;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Commons
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ロガー
|
||||||
|
/// </summary>
|
||||||
|
public static class LoggerUxer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 初期化
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="iniPath">ログINIファイルパス</param>
|
||||||
|
public static void Initialize(string iniPath)
|
||||||
|
{
|
||||||
|
EnsureIniExists(iniPath);
|
||||||
|
// var config = IniReferenceResolveUxer.ReadSectionWithReference(iniPath, "Logging");
|
||||||
|
|
||||||
|
var level = Enum.TryParse(
|
||||||
|
//config["LogLevel"],
|
||||||
|
IniHelper.ReadValue(iniPath, "Logging", "LogLevel"),
|
||||||
|
out LogEventLevel parsedLevel)
|
||||||
|
? parsedLevel
|
||||||
|
: LogEventLevel.Information;
|
||||||
|
|
||||||
|
// var path = config["LogFilePath"];
|
||||||
|
var path = IniHelper.ReadValue(iniPath, "Logging", "LogFilePath");
|
||||||
|
var rolling = IniHelper.ReadValue(iniPath, "Logging", "RollingInterval");
|
||||||
|
|
||||||
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Is(level)
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.File(path, rollingInterval: (RollingInterval)Enum.Parse(typeof(RollingInterval), rolling))
|
||||||
|
.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Info(string message) => Log.Information(message);
|
||||||
|
public static void Warn(string message) => Log.Warning(message);
|
||||||
|
public static void Error(string message) => Log.Error(message);
|
||||||
|
public static void Close() => Log.CloseAndFlush();
|
||||||
|
|
||||||
|
public static void StartInfo()
|
||||||
|
{
|
||||||
|
// DLL(自身)のアセンブリ
|
||||||
|
var dllAssembly = Assembly.GetExecutingAssembly();
|
||||||
|
var dllVersion = dllAssembly.GetName().Version?.ToString();
|
||||||
|
var dllProduct = dllAssembly.GetCustomAttribute<AssemblyProductAttribute>()?.Product ?? "不明";
|
||||||
|
|
||||||
|
// EXE(呼び出し元)のアセンブリ
|
||||||
|
var exeAssembly = Assembly.GetEntryAssembly();
|
||||||
|
var exeVersion = exeAssembly?.GetName().Version?.ToString();
|
||||||
|
var exeProduct = exeAssembly?.GetCustomAttribute<AssemblyProductAttribute>()?.Product ?? "不明";
|
||||||
|
|
||||||
|
// ログ出力
|
||||||
|
Info($"[EXE] 製品名: {exeProduct}, バージョン: {exeVersion}");
|
||||||
|
Info($"[DLL] 製品名: {dllProduct}, バージョン: {dllVersion}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ログINI初期化(無ければ)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">ログINIファイルパス</param>
|
||||||
|
private static void EnsureIniExists(string path)
|
||||||
|
{
|
||||||
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
|
File.WriteAllLines(path, new[]
|
||||||
|
{
|
||||||
|
"[Logging]",
|
||||||
|
"LogLevel=Information",
|
||||||
|
"LogFilePath=log.txt",
|
||||||
|
"RollingInterval=Day"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Commons
|
||||||
|
{
|
||||||
|
public static class RetCodeUxer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 戻り値(プロセス終了値)
|
||||||
|
/// </summary>
|
||||||
|
public enum RetCode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 成功
|
||||||
|
/// </summary>
|
||||||
|
Success = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ファイルバックアップ時エラー
|
||||||
|
/// </summary>
|
||||||
|
FileBackupError = -1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ファイルクリーンナップエラー
|
||||||
|
/// </summary>
|
||||||
|
CleanupError = -2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 開始日エラー
|
||||||
|
/// </summary>
|
||||||
|
StartDateError = -3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DB接続エラー
|
||||||
|
/// </summary>
|
||||||
|
DbConnectError = -4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SQLフォルダパス未設定
|
||||||
|
/// </summary>
|
||||||
|
SqlFolderPathNoSetting = -5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SQLファイルロードエラー
|
||||||
|
/// </summary>
|
||||||
|
SqlFileLoadError = -6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CSVファイル名パターン群が未設定
|
||||||
|
/// </summary>
|
||||||
|
CsvFileNamePatternsNotSetting = -7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 設定ファイルの要素数エラー
|
||||||
|
/// </summary>
|
||||||
|
IniFileItemCountError = -8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 挿入前の削除時に例外発生
|
||||||
|
/// </summary>
|
||||||
|
DeleteBeforeInsertException = -9,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CSVデータをDB登録時エラー
|
||||||
|
/// </summary>
|
||||||
|
InsertDbFromCsvFilesError = -10,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CSVからDB登録時に例外発生
|
||||||
|
/// </summary>
|
||||||
|
CsvToDbException = -11,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ファイル削除でフォルダパス未設定
|
||||||
|
/// </summary>
|
||||||
|
FileDeleteFolderPathNotSetting = -12,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ファイル削除でフォルダパス未存在
|
||||||
|
/// </summary>
|
||||||
|
FileDeleteFolderPathNotExist = -13,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ファイル削除でファイル名パターン未設定
|
||||||
|
/// </summary>
|
||||||
|
FileDeleteFileNamePatternNotSetting = -14,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ファイル削除でファイル名パターン削除エラー
|
||||||
|
/// </summary>
|
||||||
|
FileDeletePatternFilesError = -15,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SFTPオブジェクト生成エラー
|
||||||
|
/// </summary>
|
||||||
|
SftpObjectCreateError = -16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SFTPアップロードエラー
|
||||||
|
/// </summary>
|
||||||
|
SftpUploadError = -17,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SFTPアップロードで入力フォルダ未存在
|
||||||
|
/// </summary>
|
||||||
|
SftpInFolderPathNotExist = -18,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SFTPでCSVファイル名パターンが未設定
|
||||||
|
/// </summary>
|
||||||
|
SftpCsvFileNamePatternsNotSetting = -19,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SFTPダウンロード時に例外発生
|
||||||
|
/// </summary>
|
||||||
|
SftpDownloadException = -20,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SFTPファイル削除エラー
|
||||||
|
/// </summary>
|
||||||
|
SftpDeleteMatchingFilesError = -21,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SFTPパターンマッチファイルダウンロード時エラー
|
||||||
|
/// </summary>
|
||||||
|
SftpMatchFilesDownloadError = -22,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SFTP共通:テスト接続エラー
|
||||||
|
/// </summary>
|
||||||
|
SftpTestConnectError = -23,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Commons
|
||||||
|
{
|
||||||
|
public class StringUxer
|
||||||
|
{
|
||||||
|
public static bool WildcardMatch(string input, string pattern)
|
||||||
|
{
|
||||||
|
// "*" を ".*" に変換し、正規表現にする
|
||||||
|
string regexPattern = "^" + Regex.Escape(pattern).Replace("\\*", ".*") + "$";
|
||||||
|
return Regex.IsMatch(input, regexPattern, RegexOptions.IgnoreCase);
|
||||||
|
}
|
||||||
|
// public static bool TryParseIniSignature(string iniValue, out string functionName, out List<string> args)
|
||||||
|
// {
|
||||||
|
// functionName = null;
|
||||||
|
// args = null;
|
||||||
|
|
||||||
|
// var pattern = @"^([a-zA-Z_][a-zA-Z0-9_]*)\((.*?)\)$";
|
||||||
|
// var match = Regex.Match(iniValue.Trim(), pattern);
|
||||||
|
|
||||||
|
// if (!match.Success)
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
// functionName = match.Groups[1].Value;
|
||||||
|
// var argsString = match.Groups[2].Value;
|
||||||
|
|
||||||
|
// args = string.IsNullOrEmpty(argsString)
|
||||||
|
// ? new List<string>()
|
||||||
|
// : argsString.Split(',').Select(arg => arg.Trim()).ToList();
|
||||||
|
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static bool TryExtractYearFromString(string str, out int year)
|
||||||
|
{
|
||||||
|
// var match = Regex.Match(str, @"\b(20\d{2})\b"); // 条件厳しめ
|
||||||
|
var match = Regex.Match(str, @"(20\d{2})"); // 条件緩め
|
||||||
|
year = match.Success ? int.Parse(match.Groups[1].Value) : -1;
|
||||||
|
return year != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CSVから文字列取得(インデックス指定:範囲外の時既定値)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="csv">CSV文字列(カンマ区切り)</param>
|
||||||
|
/// <param name="index">インデックス</param>
|
||||||
|
/// <param name="noString">範囲外の時の既定値</param>
|
||||||
|
/// <returns>取得した文字列</returns>
|
||||||
|
public static string GetStringByIndexFormCsv(string csv, int index, string noString = "(No name...)")
|
||||||
|
{
|
||||||
|
string[] strSplit = csv.Split(',');
|
||||||
|
if (index < 0 || index > strSplit.Length - 1) return noString;
|
||||||
|
return strSplit[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Commons
|
||||||
|
{
|
||||||
|
public static class VariableUxer
|
||||||
|
{
|
||||||
|
private static List<string> _args = new List<string>();
|
||||||
|
|
||||||
|
public static List<string> Args { get => _args; }
|
||||||
|
public static void SetArgs(string[] args) { _args = args.ToList(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
namespace KssSmaPlaCoreLib.Crypto;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
public class SecureConfigServiceUxer(string masterKey)
|
||||||
|
{
|
||||||
|
private readonly byte[] _key = SHA256.HashData(Encoding.UTF8.GetBytes(masterKey));
|
||||||
|
|
||||||
|
public string Encrypt(string plainText)
|
||||||
|
{
|
||||||
|
var plainBytes = Encoding.UTF8.GetBytes(plainText);
|
||||||
|
var nonce = RandomNumberGenerator.GetBytes(AesGcm.NonceByteSizes.MaxSize);
|
||||||
|
var tag = new byte[AesGcm.TagByteSizes.MaxSize];
|
||||||
|
var cipherText = new byte[plainBytes.Length];
|
||||||
|
|
||||||
|
using var aes = new AesGcm(_key, tag.Length);
|
||||||
|
aes.Encrypt(nonce, plainBytes, cipherText, tag);
|
||||||
|
|
||||||
|
// [Nonce(12)] + [Tag(16)] + [Cipher]
|
||||||
|
var result = new byte[nonce.Length + tag.Length + cipherText.Length];
|
||||||
|
Buffer.BlockCopy(nonce, 0, result, 0, nonce.Length);
|
||||||
|
Buffer.BlockCopy(tag, 0, result, nonce.Length, tag.Length);
|
||||||
|
Buffer.BlockCopy(cipherText, 0, result, nonce.Length + tag.Length, cipherText.Length);
|
||||||
|
|
||||||
|
return Convert.ToBase64String(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Decrypt(string base64Text)
|
||||||
|
{
|
||||||
|
var data = Convert.FromBase64String(base64Text);
|
||||||
|
var nonce = data[..12];
|
||||||
|
var tag = data[12..28];
|
||||||
|
var cipherText = data[28..];
|
||||||
|
var plainBytes = new byte[cipherText.Length];
|
||||||
|
|
||||||
|
using var aes = new AesGcm(_key, tag.Length);
|
||||||
|
aes.Decrypt(nonce, cipherText, tag, plainBytes);
|
||||||
|
|
||||||
|
return Encoding.UTF8.GetString(plainBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
using KssSmaPlaLib.Commons;
|
||||||
|
using KssSmaPlaLib.IO.Database;
|
||||||
|
using KssSmaPlaLib.IO.File;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Exchange
|
||||||
|
{
|
||||||
|
public static class CsvDbSyncUxer
|
||||||
|
{
|
||||||
|
// public static bool InsertDbFromCsvFiles(
|
||||||
|
// DbUxer con,
|
||||||
|
// string csvFilePath,
|
||||||
|
// string dupCheckSql,
|
||||||
|
// string insertSqlName,
|
||||||
|
// out string resultMessage,
|
||||||
|
// EncodingUxer.EncodingType encodingType = EncodingUxer.EncodingType.Utf8WithoutBom)
|
||||||
|
// {
|
||||||
|
// var messageForMe = string.Empty;
|
||||||
|
|
||||||
|
// resultMessage = string.Empty;
|
||||||
|
|
||||||
|
// // CSV読み込み
|
||||||
|
// if (!CsvUxer.ImportFromCsv(csvFilePath, out var rs, out messageForMe, encodingType))
|
||||||
|
// {
|
||||||
|
// resultMessage = messageForMe;
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// LoggerUxer.Info($"[CSV件数:{rs.Count}]");
|
||||||
|
|
||||||
|
// if (string.IsNullOrEmpty(dupCheckSql))
|
||||||
|
// {
|
||||||
|
// LoggerUxer.Info($"重複チェックSQLが未指定のため重複チェックは行いません。");
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// LoggerUxer.Info($"重複チェックを行います。[SQLファイル:{dupCheckSql}]");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// foreach (var rec in rs)
|
||||||
|
// {
|
||||||
|
// var recObj = rec.ToDictionary(kvp => kvp.Key, kvp => (object)kvp.Value);
|
||||||
|
|
||||||
|
// if (!string.IsNullOrEmpty(dupCheckSql))
|
||||||
|
// {
|
||||||
|
// // 重複チェック
|
||||||
|
// if (!con.ExecuteQuery(dupCheckSql, recObj, out var dupRs, out messageForMe))
|
||||||
|
// {
|
||||||
|
// resultMessage = "重複チェックエラー:" + messageForMe;
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// if (dupRs.Count != 1)
|
||||||
|
// {
|
||||||
|
// resultMessage = $"重複チェックで取得件数エラーです。[取得件数:{dupRs.Count}]";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// // ↓COUNT(*)の結果型はintにあらず(ポスグレの場合long)ゆえに文字列化してint化する
|
||||||
|
// if (!int.TryParse(dupRs[0].Values.ElementAt(0).ToString(), out var intCnt))
|
||||||
|
// {
|
||||||
|
// resultMessage = $"重複チェックで取得値(件数)が数値ではありません。[取得値:{dupRs[0].Values.ElementAt(0)}]";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// // 重複レコードありの場合、飛ばす
|
||||||
|
// if (intCnt > 0)
|
||||||
|
// {
|
||||||
|
// LoggerUxer.Info($"重複レコードのため、飛ばします。[該当件数:{intCnt}]");
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// LoggerUxer.Info($"重複チェックにて重複レコードは見つかりませんでした。");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // DB挿入
|
||||||
|
// if (!string.IsNullOrEmpty(insertSqlName))
|
||||||
|
// {
|
||||||
|
// LoggerUxer.Info($"[DB挿入SQL名:{insertSqlName}]");
|
||||||
|
// if (!con.ExecuteNonQuery(insertSqlName, recObj, out var resultCount, out messageForMe))
|
||||||
|
// {
|
||||||
|
// resultMessage = messageForMe;
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// LoggerUxer.Info($"[DB挿入件数:{resultCount}]");
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// LoggerUxer.Info($"DB挿入SQL名が未指定のためDB挿入は行いません。");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Exchange.Interfaces
|
||||||
|
{
|
||||||
|
public interface ICsvExportableUxer
|
||||||
|
{
|
||||||
|
string CsvHeader { get; } // ヘッダー行
|
||||||
|
string ToCsvLine(); // データ行
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,605 @@
|
|||||||
|
using DocumentFormat.OpenXml.Drawing;
|
||||||
|
using DocumentFormat.OpenXml.Office.Word;
|
||||||
|
using DocumentFormat.OpenXml.Spreadsheet;
|
||||||
|
using DocumentFormat.OpenXml.Wordprocessing;
|
||||||
|
using KssSmaPlaLib.Commons;
|
||||||
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using static KssSmaPlaLib.IO.Database.DbUxer;
|
||||||
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.IO.Database
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// DBアクセスアシスタント
|
||||||
|
/// </summary>
|
||||||
|
public class DbUxer : IDisposable
|
||||||
|
{
|
||||||
|
public enum DbProvider
|
||||||
|
{
|
||||||
|
PostgreSQL,
|
||||||
|
SQLServer,
|
||||||
|
MySQL,
|
||||||
|
Oracle,
|
||||||
|
SQLite,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// プロバイダ名ディクショナリ
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Dictionary<DbProvider, string> _providerNameDic = new Dictionary<DbProvider, string>()
|
||||||
|
{
|
||||||
|
{ DbProvider.PostgreSQL, "Npgsql" },
|
||||||
|
{ DbProvider.SQLServer, "System.Data.SqlClient" },
|
||||||
|
{ DbProvider.MySQL, "MySql.Data.MySqlClient" },
|
||||||
|
{ DbProvider.Oracle, "Oracle.ManagedDataAccess.Client" },
|
||||||
|
{ DbProvider.SQLite, "System.Data.SQLite" },
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// プロバイダ名(文字列)からenum値に変更
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dbProviderName">プロバイダ名(文字列)</param>
|
||||||
|
/// <returns>enum値(該当なし時はnull)</returns>
|
||||||
|
public static DbProvider? GetDbProviderEnumFromString(string dbProviderName = "PostgreSQL")
|
||||||
|
{
|
||||||
|
switch(dbProviderName.ToLower().Replace(" ",""))
|
||||||
|
{
|
||||||
|
case "postgresql":
|
||||||
|
case "ポスグレ":
|
||||||
|
return DbProvider.PostgreSQL;
|
||||||
|
case "sqlserver":
|
||||||
|
return DbProvider.SQLServer;
|
||||||
|
case "mysql":
|
||||||
|
return DbProvider.MySQL;
|
||||||
|
case "oracle":
|
||||||
|
case "oracledatabase":
|
||||||
|
return DbProvider.Oracle;
|
||||||
|
case "sqlite":
|
||||||
|
case "sqlite3":
|
||||||
|
return DbProvider.SQLite;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// コミット済みフラグ
|
||||||
|
/// </summary>
|
||||||
|
private bool _isCommitted = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SQLディクショナリ
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Dictionary<string, string> _sqlDic = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指定フォルダからSQLファイルを読み込む(ディクショナリ保存)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">フォルダパス</param>
|
||||||
|
/// <returns>成否</returns>
|
||||||
|
public static bool TryLoadSqlFromText(string folderPath, out string resultMessage)
|
||||||
|
{
|
||||||
|
resultMessage = string.Empty;
|
||||||
|
var fileCount = 0;
|
||||||
|
List<string> files = new List<string>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(folderPath))
|
||||||
|
{
|
||||||
|
resultMessage = "フォルダパスが指定されていません。";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Directory.Exists(folderPath))
|
||||||
|
{
|
||||||
|
resultMessage = $"フォルダが存在しません。[フォルダパス:{folderPath}]";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_sqlDic.Clear();
|
||||||
|
foreach (var file in Directory.GetFiles(folderPath, "*.sql.txt"))
|
||||||
|
{
|
||||||
|
_sqlDic.Add(Path.GetFileNameWithoutExtension(file).ToLower().Replace(".sql", ""), System.IO.File.ReadAllText(file));
|
||||||
|
files.Add(Path.GetFileNameWithoutExtension(file).Replace(".sql", ""));
|
||||||
|
fileCount++;
|
||||||
|
}
|
||||||
|
resultMessage = $"SQLファイルをロードしました。[ファイル数:{fileCount},ファイル:{string.Join(",", files)}]";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
resultMessage = $"SQLファイル読み込み時にエラーが発生しました。[エラー内容:{ex.Message}]";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static bool TestConnectByDic(Dictionary<string,string> iniDic, out string resultMessage)
|
||||||
|
// {
|
||||||
|
// const string KEY_DB_PROVIDER_NAME = "DbProviderName";
|
||||||
|
// const string KEY_DB_CONNECTION_STRING = "DbConnectionString";
|
||||||
|
|
||||||
|
// var dbProviderName = DictionaryUxer.GetValueOrDefault(iniDic, KEY_DB_PROVIDER_NAME, string.Empty);
|
||||||
|
// var connectionString = DictionaryUxer.GetValueOrDefault(iniDic, KEY_DB_CONNECTION_STRING, string.Empty);
|
||||||
|
// return TestConnect(dbProviderName, connectionString, out resultMessage);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// テスト接続
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>成否</returns>
|
||||||
|
// public static bool TestConnect(string dbPrividerName, string dbConnectionString, out string resultMessage)
|
||||||
|
// {
|
||||||
|
// // パラメータチェック&DBプロバイダ取得
|
||||||
|
// if (!TryConnectParameter(dbPrividerName, dbConnectionString, out DbProvider? _, out resultMessage))
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!TryCreate(dbPrividerName, dbConnectionString, out var dbUxer, out resultMessage, false))
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// dbUxer.Dispose();
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DB接続
|
||||||
|
/// </summary>
|
||||||
|
private DbConnection? _con = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// トランザクション
|
||||||
|
/// </summary>
|
||||||
|
private DbTransaction? _tran = null;
|
||||||
|
|
||||||
|
// public static bool TryCreateByDic(Dictionary<string, string> iniDic, out DbUxer dbUxer, out string resultMessage, bool useTransaction = false)
|
||||||
|
// {
|
||||||
|
// const string KEY_DB_PROVIDER_NAME = "DbProviderName";
|
||||||
|
// const string KEY_DB_CONNECTION_STRING = "DbConnectionString";
|
||||||
|
|
||||||
|
// var dbProviderName = DictionaryUxer.GetValueOrDefault(iniDic, KEY_DB_PROVIDER_NAME, string.Empty);
|
||||||
|
// var connectionString = DictionaryUxer.GetValueOrDefault(iniDic, KEY_DB_CONNECTION_STRING, string.Empty);
|
||||||
|
|
||||||
|
// return TryCreate(dbProviderName, connectionString, out dbUxer, out resultMessage, useTransaction);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成挑戦
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dbPrividerName"></param>
|
||||||
|
/// <param name="dbProvider"></param>
|
||||||
|
/// <param name="dbConnectionString"></param>
|
||||||
|
/// <param name="dbUxer"></param>
|
||||||
|
/// <param name="resultMessage"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
// public static bool TryCreate(string dbPrividerName, string dbConnectionString, out DbUxer dbUxer, out string resultMessage, bool useTransaction = false)
|
||||||
|
// {
|
||||||
|
// dbUxer = null;
|
||||||
|
|
||||||
|
// // パラメータチェック&DBプロバイダ取得
|
||||||
|
// if (!TryConnectParameter(dbPrividerName, dbConnectionString, out DbProvider? dbp, out resultMessage))
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// DbProvider dbpp = (DbProvider)dbp;
|
||||||
|
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// // 生成
|
||||||
|
// dbUxer = new DbUxer(dbpp, dbConnectionString, useTransaction);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// catch (Exception ex)
|
||||||
|
// {
|
||||||
|
// // 接続NG回答
|
||||||
|
// resultMessage = $"DB接続に失敗しました。[エラー内容:{ex.Message}]";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
private static bool TryConnectParameter(string dbPrividerName, string dbConnectionString, out DbProvider? dbp, out string resultMessage)
|
||||||
|
{
|
||||||
|
dbp = DbProvider.PostgreSQL;
|
||||||
|
resultMessage = string.Empty;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(dbPrividerName))
|
||||||
|
{
|
||||||
|
// DBプロバイダ指定なしの場合、デフォルトはポスグレとする
|
||||||
|
// Infoメッセージ
|
||||||
|
resultMessage = "DBプロバイダ名が未指定のため、デフォルトのPostgreSQLを使用します。";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(dbConnectionString))
|
||||||
|
{
|
||||||
|
resultMessage = "接続文字列が設定されていません。";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(dbPrividerName))
|
||||||
|
{
|
||||||
|
dbp = GetDbProviderEnumFromString(dbPrividerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbp == null)
|
||||||
|
{
|
||||||
|
resultMessage = $"DBプロバイダ名が不正です。[DBプロバイダ名:{dbPrividerName}]";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// コンストラクタ(DB接続)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dbProvider">DBプロバイダ(enum値)</param>
|
||||||
|
/// <param name="connectionString">接続文字列</param>
|
||||||
|
/// <param name="useTransaction">トランザクション有無</param>
|
||||||
|
private DbUxer(DbProvider dbProvider, string connectionString, bool useTransaction = false)
|
||||||
|
{
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// // DBプロバイダファクトリー作成
|
||||||
|
// DbProviderFactory factory;
|
||||||
|
// if (dbProvider == DbProvider.PostgreSQL)
|
||||||
|
// {
|
||||||
|
// // ポスグレの場合、Npgsqlのインスタンをを直接取得
|
||||||
|
// factory = Npgsql.NpgsqlFactory.Instance;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// factory = DbProviderFactories.GetFactory(_providerNameDic[dbProvider]);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // DB接続作成
|
||||||
|
// _con = factory.CreateConnection();
|
||||||
|
|
||||||
|
// // 接続文字列設定
|
||||||
|
// _con.ConnectionString = connectionString;
|
||||||
|
|
||||||
|
// // 接続
|
||||||
|
// _con.Open();
|
||||||
|
|
||||||
|
// // トランザクション
|
||||||
|
// if (useTransaction) _tran = _con.BeginTransaction();
|
||||||
|
// }
|
||||||
|
// catch (Exception ex)
|
||||||
|
// {
|
||||||
|
// LoggerUxer.Error($"DB接続に失敗しました。[プロバイダ:{dbProvider},接続文字列:{connectionString},エラー内容:{ex.Message}]");
|
||||||
|
// throw ex;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// public bool ExecuteNonQuery(string sqlOrName, Dictionary<string, object> parameters, out int resultCount, out string resultMessage)
|
||||||
|
// {
|
||||||
|
// resultCount = 0;
|
||||||
|
// resultMessage = string.Empty;
|
||||||
|
|
||||||
|
// if (_con == null || _con.State != ConnectionState.Open)
|
||||||
|
// {
|
||||||
|
// resultMessage = "DBと接続されていません。";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// using (var cmd = _con.CreateCommand())
|
||||||
|
// {
|
||||||
|
// // コパンドプロパティを注入
|
||||||
|
// if (!TryInjectSoulToCmd(cmd, sqlOrName, parameters, out var messageForMe))
|
||||||
|
// {
|
||||||
|
// resultMessage = messageForMe;
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// resultCount = cmd.ExecuteNonQuery();
|
||||||
|
// LoggerUxer.Info($"[Rec Count:{resultCount}]");
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// catch (Exception ex)
|
||||||
|
// {
|
||||||
|
// resultMessage = $"SQL実行でエラーが発生しました。[SQL名:{sqlOrName},エラー内容:{ex.Message}]";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public bool ExecuteQuery(string sqlOrName, Dictionary<string, object> parameters, out List<Dictionary<string, object>> recordSet, out string resultMessage)
|
||||||
|
// {
|
||||||
|
// recordSet = new List<Dictionary<string, object>>();
|
||||||
|
// resultMessage = string.Empty;
|
||||||
|
|
||||||
|
// if (_con == null || _con.State != ConnectionState.Open)
|
||||||
|
// {
|
||||||
|
// resultMessage = "DBと接続されていません。";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// using (var cmd = _con.CreateCommand())
|
||||||
|
// {
|
||||||
|
// // コパンドプロパティを注入
|
||||||
|
// if (!TryInjectSoulToCmd(cmd, sqlOrName, parameters, out var messageForMe))
|
||||||
|
// {
|
||||||
|
// resultMessage = messageForMe;
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// using (var reader = cmd.ExecuteReader())
|
||||||
|
// {
|
||||||
|
// while (reader.Read())
|
||||||
|
// {
|
||||||
|
// var row = new Dictionary<string, object>();
|
||||||
|
// for (int i = 0; i < reader.FieldCount; i++)
|
||||||
|
// {
|
||||||
|
// row[reader.GetName(i)] = reader.GetValue(i);
|
||||||
|
// }
|
||||||
|
// recordSet.Add(row);
|
||||||
|
// }
|
||||||
|
// LoggerUxer.Info($"[Rec Count:{recordSet.Count}]");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// catch (Exception ex)
|
||||||
|
// {
|
||||||
|
// resultMessage = $"DBからデータ取得時にエラーが発生しました。[SQL名:{sqlOrName},エラー内容:{ex.Message}]";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private bool TryInjectSoulToCmd(DbCommand cmd, string sqlOrName, Dictionary<string,object> parameters, out string resultMessage)
|
||||||
|
// {
|
||||||
|
// resultMessage = string.Empty;
|
||||||
|
|
||||||
|
// // SQLの取得
|
||||||
|
// sqlOrName = sqlOrName.ToLower();
|
||||||
|
// var sql = _sqlDic.ContainsKey(sqlOrName) ? _sqlDic[sqlOrName] : sqlOrName;
|
||||||
|
// //LoggerUxer.Info($"[SQL:{sql}]");
|
||||||
|
|
||||||
|
// // SQL中のコマンドパラメータ名取得
|
||||||
|
// var paraList = ExtractSqlParams(sql);
|
||||||
|
// //oggerUxer.Info($"[SQL Para names:{string.Join(",", paraList)}]");
|
||||||
|
|
||||||
|
// // コマンドパラメータ値の型変換
|
||||||
|
// if (!TryChangeParamTypeFromSqlParams(ref parameters, ref paraList, out var messageForMe))
|
||||||
|
// {
|
||||||
|
// resultMessage = $"コマンドパラメータ値の型変換に失敗しました。[エラー内容:{messageForMe}]";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // SQL文中のコマンドパラメータ型定義をカット
|
||||||
|
// cmd.CommandText = sql = CutParamTypeOfSQL(sql);
|
||||||
|
// //LoggerUxer.Info($"[SQL(Param Type Cut):{sql}]");
|
||||||
|
|
||||||
|
// // 再度、SQL中のコマンドパラメータ名取得
|
||||||
|
// paraList = ExtractSqlParams(sql);
|
||||||
|
// //LoggerUxer.Info($"[SQL Para names(Type cut):{string.Join(",", paraList)}]");
|
||||||
|
|
||||||
|
// // SQLに合わせたコマンドパラメータ登録
|
||||||
|
// foreach (var p in parameters)
|
||||||
|
// {
|
||||||
|
// if (!paraList.Contains(p.Key)) continue;
|
||||||
|
// var param = cmd.CreateParameter();
|
||||||
|
// param.ParameterName = p.Key;
|
||||||
|
// param.Value = p.Value;
|
||||||
|
// cmd.Parameters.Add(param);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //LoggerUxer.Info($"[SQL Params:{GetCommandParametersCsv(cmd)}]");
|
||||||
|
|
||||||
|
// if (cmd.Parameters.Count != paraList.Count)
|
||||||
|
// {
|
||||||
|
// resultMessage = $"必要なパラメータが不足しています。[SQL名:{sqlOrName},SQL項目:{string.Join(",", paraList)}, CSV項目:{string.Join(",", parameters.Keys)}]";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public void Commit()
|
||||||
|
{
|
||||||
|
_tran?.Commit();
|
||||||
|
_isCommitted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 終了処理
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_tran != null && !_isCommitted)
|
||||||
|
{
|
||||||
|
Log.Warning("トランザクション未コミット → 自動ロールバックされました");
|
||||||
|
_tran.Rollback(); // 明示的にロールバック
|
||||||
|
}
|
||||||
|
_con?.Dispose();
|
||||||
|
_con = null;
|
||||||
|
_tran = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<string> ExtractSqlParams(string sql)
|
||||||
|
{
|
||||||
|
//var matches = System.Text.RegularExpressions.Regex.Matches(sql, @":([a-zA-Z_][a-zA-Z0-9_]*)");
|
||||||
|
//return matches.Cast<System.Text.RegularExpressions.Match>()
|
||||||
|
// .Select(m => m.Groups[1].Value)
|
||||||
|
// .Distinct()
|
||||||
|
// .ToList();
|
||||||
|
|
||||||
|
//var result = new List<string>();
|
||||||
|
//var lines = sql.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
|
||||||
|
|
||||||
|
//foreach (var line in lines)
|
||||||
|
//{
|
||||||
|
// // コメント部分を除去
|
||||||
|
// var codePart = line.Contains("--") ? line.Substring(0, line.IndexOf("--")) : line;
|
||||||
|
|
||||||
|
// // パラメータ抽出
|
||||||
|
// var matches = System.Text.RegularExpressions.Regex.Matches(
|
||||||
|
// codePart,
|
||||||
|
// @":(\[[a-zA-Z]\][a-zA-Z_][a-zA-Z0-9_]*)|:([a-zA-Z_][a-zA-Z0-9_]*)"
|
||||||
|
// );
|
||||||
|
// foreach (System.Text.RegularExpressions.Match match in matches)
|
||||||
|
// {
|
||||||
|
// var paramName = match.Groups[1].Success ? match.Groups[1].Value : match.Groups[2].Value;
|
||||||
|
// if (!result.Contains(paramName))
|
||||||
|
// result.Add(paramName);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//return result;
|
||||||
|
|
||||||
|
var result = new List<string>();
|
||||||
|
var lines = sql.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
|
||||||
|
|
||||||
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
|
// コメント部分を除去
|
||||||
|
var codePart = line.Contains("--") ? line.Substring(0, line.IndexOf("--")) : line;
|
||||||
|
|
||||||
|
// パラメータ抽出(::で始まるものは除外)
|
||||||
|
var matches = System.Text.RegularExpressions.Regex.Matches(
|
||||||
|
codePart,
|
||||||
|
@"(?<!:):(\[[a-zA-Z]\][a-zA-Z_][a-zA-Z0-9_]*)|(?<!:):([a-zA-Z_][a-zA-Z0-9_]*)"
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach (System.Text.RegularExpressions.Match match in matches)
|
||||||
|
{
|
||||||
|
var paramName = match.Groups[1].Success ? match.Groups[1].Value : match.Groups[2].Value;
|
||||||
|
if (!result.Contains(paramName))
|
||||||
|
result.Add(paramName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// public static string GetCommandParametersCsv(DbCommand command)
|
||||||
|
// {
|
||||||
|
// if (command == null || command.Parameters.Count == 0)
|
||||||
|
// return string.Empty;
|
||||||
|
|
||||||
|
// var list = new List<string>();
|
||||||
|
|
||||||
|
// foreach (DbParameter param in command.Parameters)
|
||||||
|
// {
|
||||||
|
// string name = param.ParameterName?.TrimStart('@'); // @を除去(任意)
|
||||||
|
// object value = param.Value;
|
||||||
|
|
||||||
|
// string formattedValue;
|
||||||
|
|
||||||
|
// if (value == null || value == DBNull.Value)
|
||||||
|
// {
|
||||||
|
// formattedValue = "NULL";
|
||||||
|
// }
|
||||||
|
// else if (value is string || value is char)
|
||||||
|
// {
|
||||||
|
// formattedValue = $"'{value}'"; // シングルクォートで括る
|
||||||
|
// }
|
||||||
|
// else if (value is DateTime dt)
|
||||||
|
// {
|
||||||
|
// formattedValue = $"'{dt:yyyy-MM-dd HH:mm:ss}'"; // 日付も文字列扱い
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// formattedValue = value.ToString();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// list.Add($"{name}={formattedValue}");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return string.Join(",", list);
|
||||||
|
// }
|
||||||
|
// private static bool TryChangeParamTypeFromSqlParams(ref Dictionary<string, object> parameters, ref List<string> paraNameList, out string resultMessage)
|
||||||
|
// {
|
||||||
|
// resultMessage = string.Empty;
|
||||||
|
|
||||||
|
// foreach (var key in parameters.Keys.ToList())
|
||||||
|
// {
|
||||||
|
// var name = paraNameList
|
||||||
|
// .FirstOrDefault(m => m == key || m.Substring(0, 1) == "[" && m.Substring(3) == key);
|
||||||
|
// if (name != null && name.Substring(0, 1) == "[")
|
||||||
|
// {
|
||||||
|
// switch (name.Substring(0, 3).ToUpper())
|
||||||
|
// {
|
||||||
|
// case "[I]":
|
||||||
|
// if (string.IsNullOrEmpty(parameters[key].ToString()))
|
||||||
|
// {
|
||||||
|
// parameters[key] = DBNull.Value;
|
||||||
|
// }
|
||||||
|
// else if (int.TryParse(parameters[key].ToString(), out int intValue))
|
||||||
|
// {
|
||||||
|
// parameters[key] = intValue;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// resultMessage = $"パラメータ値[I]型変換に失敗しました。[キー:{key}値:{parameters[key]}]";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// //case "[IN":
|
||||||
|
// // if (string.IsNullOrEmpty(parameters[key].ToString()))
|
||||||
|
// // {
|
||||||
|
// // parameters[key] = DBNull.Value;
|
||||||
|
// // }
|
||||||
|
// // else if (int.TryParse(parameters[key].ToString(), out intValue))
|
||||||
|
// // {
|
||||||
|
// // parameters[key] = intValue;
|
||||||
|
// // }
|
||||||
|
// // else
|
||||||
|
// // {
|
||||||
|
// // resultMessage = $"パラメータ値[IN]型変換に失敗しました。[キー:{key}値:{parameters[key]}]";
|
||||||
|
// // return false;
|
||||||
|
// // }
|
||||||
|
// // break;
|
||||||
|
// case "[F]":
|
||||||
|
// if (double.TryParse(parameters[key].ToString(), out double doubleValue))
|
||||||
|
// {
|
||||||
|
// parameters[key] = doubleValue;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// resultMessage = $"パラメータ値[F]型変換に失敗しました。[キー:{key}値:{parameters[key]}]";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// case "[D]":
|
||||||
|
// if (DateTime.TryParse(parameters[key].ToString(), out DateTime dtValue))
|
||||||
|
// {
|
||||||
|
// parameters[key] = dtValue;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// resultMessage = $"パラメータ値[D]型変換に失敗しました。[キー:{key}値:{parameters[key]}]";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// case "[S]":
|
||||||
|
// parameters[key] = parameters[key].ToString();
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// SQL文中のコマンドパラメータ型定義をカット
|
||||||
|
private static string CutParamTypeOfSQL(string sql)
|
||||||
|
{
|
||||||
|
string[] cutItems = new string[] { "[I]", "[F]", "[D]", "[S]" };
|
||||||
|
foreach (var cutItem in cutItems)
|
||||||
|
{
|
||||||
|
sql = sql.Replace(cutItem.ToUpper(), "");
|
||||||
|
sql = sql.Replace(cutItem.ToLower(), "");
|
||||||
|
}
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.IO.Excel
|
||||||
|
{
|
||||||
|
public static class ExcelCellValidatorUxer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ExcelのA1形式(例: "A1", "Z99", "AA1000")かどうかを判定します。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cellRef">セル参照文字列</param>
|
||||||
|
/// <returns>有効なA1形式ならtrue、無効ならfalse</returns>
|
||||||
|
public static bool IsValidA1Format(string cellRef)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(cellRef))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 正規表現でA1形式をチェック(列: A〜XFD、行: 1〜1048576)
|
||||||
|
var match = System.Text.RegularExpressions.Regex.Match(
|
||||||
|
cellRef.ToUpperInvariant(),
|
||||||
|
@"^([A-Z]{1,3})([1-9][0-9]{0,6})$"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!match.Success)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string colPart = match.Groups[1].Value;
|
||||||
|
string rowPart = match.Groups[2].Value;
|
||||||
|
|
||||||
|
// 列がXFD(Excel最大列)以内かチェック
|
||||||
|
if (ColumnNameToNumber(colPart) > 16384)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 行がExcel最大行以内かチェック
|
||||||
|
if (int.TryParse(rowPart, out int row))
|
||||||
|
{
|
||||||
|
return row >= 1 && row <= 1048576;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 列名(例: "A", "Z", "AA")を列番号に変換(例: 1, 26, 27)
|
||||||
|
/// </summary>
|
||||||
|
private static int ColumnNameToNumber(string columnName)
|
||||||
|
{
|
||||||
|
int sum = 0;
|
||||||
|
foreach (char c in columnName)
|
||||||
|
{
|
||||||
|
sum *= 26;
|
||||||
|
sum += (c - 'A' + 1);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.IO.Excel
|
||||||
|
{
|
||||||
|
public static class ExcelColumnHelperUxer
|
||||||
|
{
|
||||||
|
public static string GetExcelColumnLetter(int columnNumber)
|
||||||
|
{
|
||||||
|
if (columnNumber < 1)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(columnNumber), "Column number must be >= 1");
|
||||||
|
|
||||||
|
string columnLetter = string.Empty;
|
||||||
|
while (columnNumber > 0)
|
||||||
|
{
|
||||||
|
columnNumber--; // Adjust for 0-indexed calculation
|
||||||
|
columnLetter = (char)('A' + (columnNumber % 26)) + columnLetter;
|
||||||
|
columnNumber /= 26;
|
||||||
|
}
|
||||||
|
return columnLetter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
using ClosedXML.Excel;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.IO.Excel
|
||||||
|
{
|
||||||
|
public class XlUxer
|
||||||
|
{
|
||||||
|
public static IXLCell GCell(IXLWorksheet sheet, string a1Address)
|
||||||
|
{
|
||||||
|
var cell = sheet.Cell(a1Address);
|
||||||
|
return GCell(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IXLCell GCell(IXLWorksheet sheet, int row, int col)
|
||||||
|
{
|
||||||
|
var cell = sheet.Cell(row, col);
|
||||||
|
return GCell(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IXLCell GCell(IXLCell cell)
|
||||||
|
{
|
||||||
|
return cell.IsMerged() ? cell.MergedRange().FirstCell() : cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static bool TryValidateA1CellAddress(string a1Address, out string normalizedAddress)
|
||||||
|
// {
|
||||||
|
// normalizedAddress = null;
|
||||||
|
|
||||||
|
// if (string.IsNullOrWhiteSpace(a1Address))
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
// // 正規表現でA1形式(例:A1, B2, AA10など)をチェック
|
||||||
|
// var regex = new Regex(@"^[A-Z]{1,3}[1-9][0-9]*$", RegexOptions.IgnoreCase);
|
||||||
|
// if (!regex.IsMatch(a1Address))
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
// // 正規化(大文字化)
|
||||||
|
// normalizedAddress = a1Address.ToUpperInvariant();
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shorter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="colLetter"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int GetColNo(string colLetter)
|
||||||
|
{
|
||||||
|
if (!TryConvertColLetterToNumber(colLetter, out var no))
|
||||||
|
{
|
||||||
|
return int.MinValue;
|
||||||
|
}
|
||||||
|
return no;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 列アルファベットを列番号(1オリジン)に変換
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="colLetter">列アルファベット</param>
|
||||||
|
/// <param name="colNo">[出力]列番号(1オリジン)</param>
|
||||||
|
/// <returns>成否</returns>
|
||||||
|
public static bool TryConvertColLetterToNumber(string colLetter, out int colNo)
|
||||||
|
{
|
||||||
|
colNo = int.MinValue;
|
||||||
|
|
||||||
|
// バリデ(A~XFD)
|
||||||
|
if(!Regex.IsMatch(colLetter, @"^(?i)([A-Z]|[A-Z]{2}|[A-E][A-Z]{2})$"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 大文字化
|
||||||
|
colLetter = colLetter.ToUpper();
|
||||||
|
|
||||||
|
// アルファベット1文字ずつ見て列番号を算出
|
||||||
|
int no = 0;
|
||||||
|
foreach (char c in colLetter)
|
||||||
|
{
|
||||||
|
no = no * 26 + (c - 'A' + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 列番号範囲外なら失敗
|
||||||
|
if (no > 16384 || no < 1) return false;
|
||||||
|
|
||||||
|
// 成功
|
||||||
|
colNo = no;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
using KssSmaPlaLib.Commons;
|
||||||
|
using KssSmaPlaLib.Exchange.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.IO.File
|
||||||
|
{
|
||||||
|
public class CsvUxer
|
||||||
|
{
|
||||||
|
public static bool ExportToCsv<T>(List<T> list, string filePath, out string resultMessage, EncodingUxer.EncodingType encodingType = EncodingUxer.EncodingType.Utf8WithoutBom) where T : ICsvExportableUxer
|
||||||
|
{
|
||||||
|
resultMessage = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var lines = new List<string> { list.FirstOrDefault()?.CsvHeader ?? "" };
|
||||||
|
lines.AddRange(list.Select(item => item.ToCsvLine()));
|
||||||
|
System.IO.File.WriteAllLines(filePath, lines, EncodingUxer.GetEncoding(encodingType));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
resultMessage = $"CSV出力に失敗しました。[ファイルパス:{filePath},エラー内容:{ex.Message}]";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CSVインポート
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="csvFilePath">CSVファイルパス</param>
|
||||||
|
/// <param name="recordSet">[出力]レコードセット</param>
|
||||||
|
/// <param name="resultMessage">[出力]メッセージ</param>
|
||||||
|
/// <param name="encodingType">[オプション]エンコード</param>
|
||||||
|
/// <returns>成否</returns>
|
||||||
|
public static bool ImportFromCsv(string csvFilePath, out List<Dictionary<string, string>> recordSet, out string resultMessage, EncodingUxer.EncodingType encodingType = EncodingUxer.EncodingType.Utf8WithoutBom)
|
||||||
|
{
|
||||||
|
recordSet = new List<Dictionary<string, string>>();
|
||||||
|
resultMessage = string.Empty;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 全行読み込み
|
||||||
|
var lines = System.IO.File.ReadAllLines(csvFilePath, EncodingUxer.GetEncoding(encodingType));
|
||||||
|
|
||||||
|
// データ行0件
|
||||||
|
if (lines.Length < 2) return true;
|
||||||
|
|
||||||
|
// ヘッダ行項目分割
|
||||||
|
var header = Regex.Split(lines[0], ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
|
||||||
|
for (var cnt = 0; cnt < header.Length; cnt++) header[cnt] = header[cnt].Trim('\"');
|
||||||
|
|
||||||
|
// データ行件数分
|
||||||
|
for (int i = 1; i < lines.Length; i++)
|
||||||
|
{
|
||||||
|
// 項目分割
|
||||||
|
var values = Regex.Split(lines[i], ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
|
||||||
|
for (var cnt = 0; cnt < values.Length; cnt++) values[cnt] = values[cnt].Trim('\"');
|
||||||
|
|
||||||
|
if (values.Length != header.Length)
|
||||||
|
{
|
||||||
|
resultMessage = $"CSV読み込みでヘッダの項目数とデータの項目数が異なります。[CSVファイルパス:{csvFilePath},行番号:{i + 1},ヘッダ行項目数:{header.Length},データ行項目数:{values.Length}]";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var record = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
// 全項目
|
||||||
|
for (int j = 0; j < header.Length && j < values.Length; j++)
|
||||||
|
{
|
||||||
|
var key = header[j].Trim('\"');
|
||||||
|
var value = values[j].Trim('\"');
|
||||||
|
record[key] = value;
|
||||||
|
}
|
||||||
|
recordSet.Add(record);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
resultMessage = $"CSV読み込み処理でエラーが発生しました。[CSVファイルパス:{csvFilePath},エラー内容:{ex.Message}]";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Escape(string value) => $"\"{value.Replace("\"", "\"\"")}\"";
|
||||||
|
// public static string Join(params object[] values) => string.Join(",", values.Select(m => Escape(m == null ? "" : m.ToString())));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
using DocumentFormat.OpenXml.Vml;
|
||||||
|
using KssSmaPlaLib.Commons;
|
||||||
|
using KssSmaPlaLib.Exchange.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.IO.File
|
||||||
|
{
|
||||||
|
public static class FileUxer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// テキストファイル出力(全テキスト一括)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="allLineText">全テキスト</param>
|
||||||
|
/// <param name="filePath">ファイルパス</param>
|
||||||
|
/// <param name="resultMessage">メッセージ</param>
|
||||||
|
/// <param name="encodingType">文字コード</param>
|
||||||
|
/// <returns>成否</returns>
|
||||||
|
public static bool WriteAllText(string allLineText, string filePath, out string resultMessage, EncodingUxer.EncodingType encodingType = EncodingUxer.EncodingType.Utf8WithoutBom)
|
||||||
|
{
|
||||||
|
resultMessage = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
System.IO.File.WriteAllText(filePath, allLineText, EncodingUxer.GetEncoding(encodingType));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
resultMessage = $"CSV出力に失敗しました。[ファイルパス:{filePath},エラー内容:{ex.Message}]";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryDeletePatternFiles(
|
||||||
|
string folderPath,
|
||||||
|
string fileNamePattern,
|
||||||
|
out int fileCount,
|
||||||
|
out string resultMessage)
|
||||||
|
{
|
||||||
|
fileCount = 0;
|
||||||
|
resultMessage = string.Empty;
|
||||||
|
if (!Directory.Exists(folderPath))
|
||||||
|
{
|
||||||
|
resultMessage = $"フォルダが存在しません。[フォルダパス:{folderPath}]";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var files = Directory.GetFiles(folderPath, fileNamePattern);
|
||||||
|
|
||||||
|
foreach (var filePath in files)
|
||||||
|
{
|
||||||
|
System.IO.File.Delete(filePath);
|
||||||
|
fileCount++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
resultMessage = $"ファイル削除中にエラーが発生しました。[フォルダパス:{folderPath},ファイル名パターン:{fileNamePattern},エラー内容:{ex.Message}]";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetTimestampedFileName(string originalName, DateTime dt, string prefixDtFormat, string suffixDtFormat)
|
||||||
|
{
|
||||||
|
string nameWithoutExt = Path.GetFileNameWithoutExtension(originalName);
|
||||||
|
string ext = Path.GetExtension(originalName);
|
||||||
|
string prefixDtStr = dt.ToString(prefixDtFormat);
|
||||||
|
string suffixDtStr = dt.ToString(suffixDtFormat);
|
||||||
|
|
||||||
|
string newName = prefixDtStr + nameWithoutExt + suffixDtStr;
|
||||||
|
return newName + ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static bool CheckParentFolderExists(string folderPath, out string parentPath)
|
||||||
|
// {
|
||||||
|
// parentPath = Path.GetDirectoryName(folderPath) ?? string.Empty;
|
||||||
|
// return Directory.Exists(parentPath);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public static bool TryApplyActionToFiles<T>(
|
||||||
|
// string folderPath,
|
||||||
|
// Func<FileInfo, bool> condition,
|
||||||
|
// Action<FileInfo> action,
|
||||||
|
// out int fileCount,
|
||||||
|
// out string resultMessage,
|
||||||
|
// string actionName = "操作",
|
||||||
|
// bool isDescending = true,
|
||||||
|
// Func<FileInfo, T>? sortKey = null,
|
||||||
|
// int skip = 0)
|
||||||
|
// {
|
||||||
|
// fileCount = 0;
|
||||||
|
// resultMessage = string.Empty;
|
||||||
|
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// // 条件未指定時は全件対象
|
||||||
|
// condition = condition ?? (_ => true);
|
||||||
|
|
||||||
|
// // 一旦条件で取得
|
||||||
|
// var files = new DirectoryInfo(folderPath)
|
||||||
|
// .GetFiles()
|
||||||
|
// .Where(condition);
|
||||||
|
|
||||||
|
// // ソートキー作成
|
||||||
|
// var keySelector =
|
||||||
|
// sortKey != null ? (Func<FileInfo, object>)
|
||||||
|
// (f => sortKey(f)) : f => f.LastWriteTime;
|
||||||
|
|
||||||
|
// // ソート+スキップ+リスト化
|
||||||
|
// var filesList =
|
||||||
|
// (isDescending ?
|
||||||
|
// files.OrderByDescending(keySelector) :
|
||||||
|
// files.OrderBy(keySelector))
|
||||||
|
// .Skip(skip)
|
||||||
|
// .ToList();
|
||||||
|
|
||||||
|
// foreach (var file in filesList)
|
||||||
|
// {
|
||||||
|
// action(file);
|
||||||
|
// LoggerUxer.Info($"{actionName}しました。[{file}]");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fileCount = filesList.Count;
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// catch (Exception ex)
|
||||||
|
// {
|
||||||
|
// resultMessage = $"ファイル群の{actionName}に失敗しました。[エラー内容:{ex.Message}]";
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 = 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;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
using KssSmaPlaLib.Commons;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.IO.File
|
||||||
|
{
|
||||||
|
public static class PathUxer
|
||||||
|
{
|
||||||
|
public static string CreateFullPathEx(
|
||||||
|
string folderPath,
|
||||||
|
string fileName,
|
||||||
|
string dtPrefix = "",
|
||||||
|
string dtSuffix = "")
|
||||||
|
{
|
||||||
|
DateTime now = DateTime.Now;
|
||||||
|
|
||||||
|
// フォルダ:未指定時はカレントフォルダ
|
||||||
|
folderPath = string.IsNullOrEmpty(folderPath) ? "." : folderPath;
|
||||||
|
|
||||||
|
// ファイル名:未指定時は"noname.txt"とする
|
||||||
|
fileName = string.IsNullOrEmpty(fileName) ? "noname.txt" : fileName;
|
||||||
|
|
||||||
|
if (fileName.IndexOf('.') == -1)
|
||||||
|
{
|
||||||
|
// 拡張子がないとき、付与する
|
||||||
|
fileName += ".txt";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ファイルパス
|
||||||
|
var path = Path.Combine(
|
||||||
|
Path.GetFullPath(folderPath),
|
||||||
|
(string.IsNullOrEmpty(dtPrefix) ? "" : now.ToString(dtPrefix)) +
|
||||||
|
fileName.Split('.')[0] +
|
||||||
|
(string.IsNullOrEmpty(dtSuffix) ? "" : now.ToString(dtSuffix)) +
|
||||||
|
"." +
|
||||||
|
fileName.Split('.')[1]);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CombineUnixPath(params string[] parts)
|
||||||
|
{
|
||||||
|
return string.Join("/", parts.Select(p => p.Trim('/')));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ファイル名(パス不可)を受け取り、存在すればフルパスを返す。
|
||||||
|
/// 探索順:①このDLLのフォルダ → ②エントリEXEのフォルダ → ③AppDomain.BaseDirectory
|
||||||
|
/// (C)昼コパソフトウェア㈱
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileName">パスではないファイル名のみ(例: "config.json")。</param>
|
||||||
|
/// <param name="fullPath">見つかったファイルのフルパス。未発見時は null。</param>
|
||||||
|
/// <returns>発見した場合 true、未発見の場合 false。</returns>
|
||||||
|
// public static bool TryResolveInAssemblyFolder(string fileName, out string fullPath)
|
||||||
|
// {
|
||||||
|
// fullPath = null;
|
||||||
|
|
||||||
|
// // --- ガード:パスを排除(「ファイル名のみ」の前提を厳守) ---
|
||||||
|
// if (string.IsNullOrWhiteSpace(fileName))
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
// // ディレクトリ成分が入っていたら拒否
|
||||||
|
// if (!string.Equals(fileName, Path.GetFileName(fileName), StringComparison.Ordinal))
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
// // 予約文字の簡易チェック(Windows前提の一般的なNG文字)
|
||||||
|
// foreach (var ch in Path.GetInvalidFileNameChars())
|
||||||
|
// {
|
||||||
|
// if (fileName.IndexOf(ch) >= 0)
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // --- ① このメソッドを含むライブラリ(DLL)のフォルダ ---
|
||||||
|
// var dllFolder = SafeGetDirectoryName(SafeGetAssemblyLocation(Assembly.GetExecutingAssembly()));
|
||||||
|
// if (TryCombineAndExists(dllFolder, fileName, out fullPath))
|
||||||
|
// return true;
|
||||||
|
|
||||||
|
// // --- ② エントリアセンブリ(EXE)のフォルダ ---
|
||||||
|
// string exeFolder = null;
|
||||||
|
// var entry = Assembly.GetEntryAssembly();
|
||||||
|
// if (entry != null)
|
||||||
|
// {
|
||||||
|
// exeFolder = SafeGetDirectoryName(SafeGetAssemblyLocation(entry));
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// // サービスや特殊ホストで EntryAssembly が null の場合のフォールバック
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// exeFolder = SafeGetDirectoryName(Process.GetCurrentProcess()?.MainModule?.FileName);
|
||||||
|
// }
|
||||||
|
// catch
|
||||||
|
// {
|
||||||
|
// // 取れないケースもあるので無理せず次へ
|
||||||
|
// exeFolder = null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (TryCombineAndExists(exeFolder, fileName, out fullPath))
|
||||||
|
// return true;
|
||||||
|
|
||||||
|
// // --- ③ AppDomain 基準(ClickOnce等のケースでも安定) ---
|
||||||
|
// var baseDir = AppDomain.CurrentDomain?.BaseDirectory;
|
||||||
|
// if (TryCombineAndExists(baseDir, fileName, out fullPath))
|
||||||
|
// return true;
|
||||||
|
|
||||||
|
// // --- 未発見 ---
|
||||||
|
// fullPath = null;
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指定フォルダに fileName を結合し、存在すれば out に設定して true。
|
||||||
|
/// </summary>
|
||||||
|
// private static bool TryCombineAndExists(string folder, string fileName, out string path)
|
||||||
|
// {
|
||||||
|
// path = null;
|
||||||
|
// if (string.IsNullOrWhiteSpace(folder))
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// var candidate = Path.Combine(folder, fileName);
|
||||||
|
// if (System.IO.File.Exists(candidate))
|
||||||
|
// {
|
||||||
|
// path = candidate;
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// catch
|
||||||
|
// {
|
||||||
|
// // パス結合や存在確認で例外が出てもスキップして未発見扱い
|
||||||
|
// }
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Assembly.Location を安全に取得(Reflection-only / 影響ケースを考慮)。
|
||||||
|
/// </summary>
|
||||||
|
// private static string SafeGetAssemblyLocation(Assembly asm)
|
||||||
|
// {
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// return asm?.Location;
|
||||||
|
// }
|
||||||
|
// catch
|
||||||
|
// {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DirectoryName を安全に取得。
|
||||||
|
/// </summary>
|
||||||
|
// private static string SafeGetDirectoryName(string path)
|
||||||
|
// {
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// return string.IsNullOrEmpty(path) ? null : Path.GetDirectoryName(path);
|
||||||
|
// }
|
||||||
|
// catch
|
||||||
|
// {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Inbox
|
||||||
|
{
|
||||||
|
public static class ProcessUxer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// EXEの同期起動(終了待ち)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exePath">実行するEXEパス</param>
|
||||||
|
/// <param name="arguments">起動時引数</param>
|
||||||
|
/// <param name="retCode">終了コード</param>
|
||||||
|
/// <param name="resultMessage">メッセージ</param>
|
||||||
|
/// <returns>成否</returns>
|
||||||
|
public static bool TryRunExeSync(string exePath, string arguments, out int retCode, out string resultMessage)
|
||||||
|
{
|
||||||
|
resultMessage = string.Empty;
|
||||||
|
retCode = -1;
|
||||||
|
|
||||||
|
// StartInfoで起動オプションを細かく制御
|
||||||
|
var startInfo = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = exePath,
|
||||||
|
Arguments = arguments,
|
||||||
|
CreateNoWindow = true, // 背後でこっそり動かす(UXの邪魔をしない)
|
||||||
|
UseShellExecute = false, // Win32 API直叩きに近い挙動(INI派ならこっち!)
|
||||||
|
RedirectStandardError = true, // エラー出力を捕まえる準備
|
||||||
|
RedirectStandardOutput = true, // 標準出力を捕まえる準備
|
||||||
|
WorkingDirectory = Path.GetDirectoryName(exePath), // 作業ディレクトリを切り替える(EXE格納フォルダ)
|
||||||
|
};
|
||||||
|
|
||||||
|
using var process = Process.Start(startInfo);
|
||||||
|
if (process == null)
|
||||||
|
{
|
||||||
|
resultMessage = "起動(Process.Start())に失敗しました。";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【ここが心臓部】完全終了を待つ
|
||||||
|
process.WaitForExit();
|
||||||
|
|
||||||
|
// 終了コードを返して、呼び出し側で「驚きのリカバリ」をさせる
|
||||||
|
retCode = process.ExitCode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Ini
|
||||||
|
{
|
||||||
|
public static class IniHelper
|
||||||
|
{
|
||||||
|
private const string INI_PATH = @".\Settings.ini";
|
||||||
|
|
||||||
|
// Win32 API宣言
|
||||||
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern int GetPrivateProfileString(
|
||||||
|
string lpAppName,
|
||||||
|
string lpKeyName,
|
||||||
|
string lpDefault,
|
||||||
|
StringBuilder lpReturnedString,
|
||||||
|
int nSize,
|
||||||
|
string lpFileName);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern bool WritePrivateProfileString(
|
||||||
|
string lpAppName,
|
||||||
|
string lpKeyName,
|
||||||
|
string lpString,
|
||||||
|
string lpFileName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// INIファイルから値を読み込み(セクション+キー指定)
|
||||||
|
/// </summary>
|
||||||
|
public static string ReadValue(string? iniPath, string section, string key, string defaultValue = "")
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(iniPath)) iniPath = INI_PATH;
|
||||||
|
var sb = new StringBuilder(1024);
|
||||||
|
GetPrivateProfileString(section, key, defaultValue, sb, sb.Capacity, iniPath);
|
||||||
|
var str = sb.ToString();
|
||||||
|
str = string.IsNullOrEmpty(str) ? defaultValue : str;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// INIファイルに値を書き込み(セクション+キー+値指定)
|
||||||
|
/// </summary>
|
||||||
|
public static bool WriteValue(string iniPath, string section, string key, string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(iniPath)) iniPath = INI_PATH;
|
||||||
|
return WritePrivateProfileString(section, key, value, iniPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using KssSmaPlaLib.Commons;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Ini
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// INIリーダー
|
||||||
|
/// </summary>
|
||||||
|
public static class IniReaderUxer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 指定セクションのINI値読み込み
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">INIパス</param>
|
||||||
|
/// <param name="section">セクション</param>
|
||||||
|
/// <returns>指定のディクショナリ</returns>
|
||||||
|
public static Dictionary<string, string> ReadSection(string path, string section)
|
||||||
|
{
|
||||||
|
var result = new Dictionary<string, string>();
|
||||||
|
var lines = File.ReadAllLines(path);
|
||||||
|
bool inSection = false;
|
||||||
|
|
||||||
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
|
var trimmed = line.Trim();
|
||||||
|
|
||||||
|
// コメント行は飛ばす
|
||||||
|
if (trimmed.StartsWith(";")) continue;
|
||||||
|
|
||||||
|
if (trimmed.StartsWith("[") && trimmed.EndsWith("]"))
|
||||||
|
inSection = trimmed == $"[{section}]";
|
||||||
|
else if (inSection && trimmed.Contains("="))
|
||||||
|
{
|
||||||
|
var index = trimmed.IndexOf('=');
|
||||||
|
if (index > 0)
|
||||||
|
{
|
||||||
|
var key = trimmed.Substring(0, index).Trim();
|
||||||
|
var value = trimmed.Substring(index + 1).Trim();
|
||||||
|
result[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// public static bool IsEmptyByIniDic(Dictionary<string,string> iniDic,string key)
|
||||||
|
// {
|
||||||
|
// return string.IsNullOrEmpty(DictionaryUxer.GetValueOrDefault(iniDic, key, string.Empty));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KssSmaPlaLib.Ini
|
||||||
|
{
|
||||||
|
public static class IniReferenceResolveUxer
|
||||||
|
{
|
||||||
|
// public static Dictionary<string, string> ReadSectionWithReference(string path, string section, int maxDepth = 3)
|
||||||
|
// {
|
||||||
|
// var allLines = File.ReadAllLines(path);
|
||||||
|
// var allSections = ParseAllSections(allLines);
|
||||||
|
// var result = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
// if (!allSections.ContainsKey(section)) return result;
|
||||||
|
|
||||||
|
// foreach (var kvp in allSections[section])
|
||||||
|
// {
|
||||||
|
// result[kvp.Key] = ResolveValue(allSections, kvp.Value, maxDepth);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private static Dictionary<string, Dictionary<string, string>> ParseAllSections(string[] lines)
|
||||||
|
// {
|
||||||
|
// var sections = new Dictionary<string, Dictionary<string, string>>();
|
||||||
|
// string currentSection = null;
|
||||||
|
|
||||||
|
// foreach (var line in lines)
|
||||||
|
// {
|
||||||
|
// var trimmed = line.Trim();
|
||||||
|
// if (trimmed.StartsWith(";") || string.IsNullOrEmpty(trimmed)) continue;
|
||||||
|
|
||||||
|
// if (trimmed.StartsWith("[") && trimmed.EndsWith("]"))
|
||||||
|
// {
|
||||||
|
// currentSection = trimmed.Substring(1, trimmed.Length - 2);
|
||||||
|
// sections[currentSection] = new Dictionary<string, string>();
|
||||||
|
// }
|
||||||
|
// else if (currentSection != null && trimmed.Contains("="))
|
||||||
|
// {
|
||||||
|
// var index = trimmed.IndexOf('=');
|
||||||
|
// var key = trimmed.Substring(0, index).Trim();
|
||||||
|
// var value = trimmed.Substring(index + 1).Trim();
|
||||||
|
// sections[currentSection][key] = value;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return sections;
|
||||||
|
// }
|
||||||
|
|
||||||
|
private static string ResolveValue(Dictionary<string, Dictionary<string, string>> sections, string value, int depth)
|
||||||
|
{
|
||||||
|
if (depth <= 0 || string.IsNullOrEmpty(value)) return value;
|
||||||
|
|
||||||
|
var match = System.Text.RegularExpressions.Regex.Match(value, @"^\{\[(.+?)\](.+?)\}$");
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
var refSection = match.Groups[1].Value;
|
||||||
|
var refKey = match.Groups[2].Value;
|
||||||
|
|
||||||
|
if (sections.ContainsKey(refSection) && sections[refSection].ContainsKey(refKey))
|
||||||
|
{
|
||||||
|
var nextValue = sections[refSection][refKey];
|
||||||
|
return ResolveValue(sections, nextValue, depth - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="ClosedXML" Version="0.105.0" />
|
||||||
|
<PackageReference Include="DocumentFormat.OpenXml" Version="3.4.1" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||||
|
<PackageReference Include="Npgsql" Version="10.0.1" />
|
||||||
|
<PackageReference Include="Serilog" Version="4.3.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.14.36908.2 d17.14
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KssSmaPlaCoreLib", "KssSmaPlaCoreLib.csproj", "{680CA95F-659F-DE7C-BF8A-20EFEA388670}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{680CA95F-659F-DE7C-BF8A-20EFEA388670}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{680CA95F-659F-DE7C-BF8A-20EFEA388670}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{680CA95F-659F-DE7C-BF8A-20EFEA388670}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{680CA95F-659F-DE7C-BF8A-20EFEA388670}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {46965DA1-5866-490A-9CE6-A0D86383B664}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
Reference in New Issue
Block a user