『格格不入』是中文IT技术交流平台，创建于2017年，包含原创博客、技术分享、资源下载等服务，提供原创、优质、完整内容的专业IT技术开发社区（前沿技术分享,你我共同成长）。
别再自己折腾了！Claude Code 订阅、Codex 订阅、ChatGPT订阅代充值一站式搞定，自动发货超省心🏁先说重点，购买地址：高校版大模型官网专业充值最近不少朋友在后台问我：Claude Pro 怎么充值？GPT Plus 哪里买靠谱？Grok 有没有便宜渠道？自己折腾半天，不是卡在支付环节，就是买到黑号被封，钱花了时间也浪费了。其实这些问题可以一次性解决。今天给大家推荐一个我自己在用的稳定渠道——高校版大模型共享站，主打自动发货 + 质保服务，价格透明，省去中间商差价。当下AI大模型迎来“超级更新月”2026年5月，各大模型密集发布重磅更新，现在正是AI使用的黄金窗口期。OpenAI方面：GPT-5.5 Instant 成为ChatGPT新一代默认模型，在保持低延迟的同时，法律、医疗、金融等敏感领域的“幻觉”问题下降约52.5%，AIME数学测试得分81.2（前代65.4），多模态推理得分76.0（前代69.2）。个性化记忆功能能够回溯过往对话、文件及Gmail内容，目前率先向Plus和Pro用户开放。Claude方面：Anthropic在开发者大会上连放数个大招，将Pro/Max用户Claude Code调用限额翻倍（5小时→10小时），取消高峰期额度削减限制，并大幅放宽Claude Opus模型的API速率。同时与SpaceX达成合作，新增超过22万张英伟达GPU算力，用于提升Pro/Max订阅用户的使用体验。Grok方面：马斯克最新宣布，Grok基础模型V9-Medium（1.5T）已完成训练，预计2-3周后正式发布，与当前v8-small模型相比将有重大提升，尤其在复杂编码任务方面。可以说，各平台都在持续投入优化，现在订阅正是时候。但问题来了——国内用户怎么支付？国内用户充值AI服务的最大痛点进入2026年，OpenAI支付网关Stripe的风控算法愈发严格，国内用户遭遇“Your card has been declined”的概率高达90%。机房IP会被直接识别拦截，国内几乎所有Visa/Mastercard都在黑名单中，2025年倒闭的大批虚拟卡号段也已被彻底屏蔽。当前五种充值方案对比方案成功率支付方式门槛推荐指数官方授权卡密（本平台）99%支付宝/微信极低⭐⭐⭐⭐⭐Apple IAP内购95%美区礼品卡中⭐⭐⭐⭐API直接调用85%信用卡/余额高⭐⭐⭐虚拟信用卡35%虚拟币/转账极高⭐共享/合租号90%支付宝/微信极简❌（严重隐私风险）根据权威测评，在支付环境日益严苛的今天，“官方授权代充”已成为成功率最高的通解，成功率可达99%。本平台正是基于这一模式，使用海外原生住宅IP和企业级正规卡池，通过官方授权接口完成订阅，3分钟即可到账，完全规避本地支付环境带来的封号风险。2026年最新价格一览（5月25日更新）商品价格质保发货方式Claude 官网账号5元/个—自动发货Claude Pro 充值（质保版）170元/月✅ 质保自助充值Claude Pro 充值（无质保版）125元/月❌ 无质保自动发货GPT Plus 充值144元✅ 质保自助充值Grok Super 充值130元✅ 质保自助充值Gmail 谷歌邮箱账号（美区）9.9元/个—自动发货[scode type="blue" size="simple"]所有标“自动发货”的商品，下单后秒到账，不需要等客服，凌晨三点也能买。[/scode]不同需求怎么选？只想低成本体验Claude：买5元的官网普号，登录即用，适合尝鲜。目前Claude Pro正放宽调用限制、提升体验，普通账号也能体验基础能力。长期使用Claude Pro：建议选170元质保版。万一账号异常，免费补发或退款，比125元无质保版多一份安心。尤其Claude近期大幅提升了使用额度，Pro用户价值更高。GPT Plus/Grok重度用户：GPT Plus现在可以用上GPT-5.5 Instant的个性化记忆功能，Grok也即将迎来V9-Medium大版本升级，现在充值正当时。GPT Plus 144元、Grok Super 130元，都是质保价。注册海外服务需要邮箱：9.9元美区Gmail，干净稳定，自动发货。官方充值入口（建议收藏）用途链接卡密购买（全品类入口）plus.gptshare666.proGPT Plus 自助充值www.czgpt.plusClaude 充值quickplus.vipGrok 充值quickplus.vip/public/grok所有链接均为自助式，不需要反复问客服，跟着页面提示操作即可。下单后系统自动发货，卡密即时可用。质保说明质保版：在有效期内如账号被封、无法登录，可联系客服免费补发或退款。建议主力使用的朋友选质保版，多一层保障。无质保版：价格更低，但无售后。适合临时测试或自行会处理问题的朋友。客服与售后充值遇到问题、需要开票，请联系QQ群群主。QQ群号：727366519（群名：高校版大模型共享站）点击加群：https://qm.qq.com/q/n7CM6MlKjm群里也有不少用户分享使用经验，可以一起交流。给新朋友的三个建议固定节点，避免风控：频繁切换IP是触发风控的首要原因，建议固定使用同一个干净的节点。拒绝共享账号：2026年各大平台已能精准识别多地并发登录，合租号不仅对话隐私无保障，还极易因他人违规操作导致整号被封。及时绑定：有真实手机号验证的账号，在遭遇误封申诉时权重远高于空号。在AI时代，时间比折腾更值钱。与其花几个小时折腾支付、冒险买黑号，不如在靠谱渠道一站式搞定。这个渠道我自己用了几个月，稳定性和响应速度都过关。有需要的朋友直接去链接下单，自动发货真的很省心。[scode type="blue" size="simple"]注：本文仅为真实使用推荐，非官方合作。价格及质保政策以站点实时公告为准。[/scode]
手把手教你安装 Claude Code CLI，接入 DeepSeek 等国产大模型
小白也能学会！手把手教你安装 Claude Code CLI，接入 DeepSeek 等国产大模型一、前言Claude Code CLI 是 Anthropic 官方推出的命令行编程助手工具。你可以在终端里直接跟 AI 对话，让它帮你写代码、改 Bug、解释项目结构，甚至执行 Git 操作和终端命令。简单说——把你的终端变成 AI 结对编程搭档。本文面向零基础或刚入门的读者，全程图文式讲解，内容包括：安装前的环境准备在 macOS / Windows 上安装 Claude Code CLI在国内网络下避开官方登录，接入 DeepSeek 等国产大模型 API几个最常用的命令和技巧二、安装前的准备工作在正式开始安装之前，请先确保你的电脑满足以下条件。2.1 环境要求系统要求macOSmacOS 11 (Big Sur) 或更高版本WindowsWindows 10 / 11，64 位Linuxx86_64, glibc 2.27+2.2 安装 Node.js（必须）Claude Code CLI 基于 Node.js，所以你需要在电脑上安装 Node.js 18 或更高版本。安装步骤：打开浏览器，访问 https://nodejs.org下载 LTS（长期支持） 版本（左侧按钮，标记为 "LTS"）双击下载好的安装包Windows：一路点击 "Next"；macOS：一路点击 "继续" → "安装"安装完成后，重启终端验证是否成功：打开终端（macOS 的"终端.app"，或 Windows 的"命令提示符 / PowerShell"），输入：node --version npm --version如果能看到版本号（例如 v18.20.0 和 10.5.0），说明安装成功。[scode type="blue" size="small"]💡 npm 是 Node.js 自带的包管理器，后续安装 Claude Code CLI 要用到它，不需要单独安装。[/scode]2.3 网络环境说明（国内用户注意事项）由于 npm 默认镜像源在国外，国内用户安装时可能遇到下载慢或超时失败的问题。推荐在安装前配置淘宝镜像源（加速 npm 包的下载）：npm config set registry https://registry.npmmirror.com配置后下载速度会显著提升，且只影响包下载，不影响后续使用。2.4 Git（可选但推荐）虽然不是强制要求，但 Claude Code 很多功能（查看代码变更、创建 PR 等）都依赖 Git。如果你还没有安装：macOS： 终端运行 git --version，如果未安装会自动弹出安装提示Windows： 访问 https://git-scm.com 下载安装安装完成后配置用户名和邮箱：git config --global user.name "你的名字" git config --global user.email "你的邮箱"三、安装 Claude Code CLI3.1 macOS 安装步骤使用 npm 安装（推荐，两种平台通用）：npm install -g @anthropic-ai/claude-code参数说明：-g 表示全局安装，安装后可以在任意目录下直接使用 claude 命令。备用方案：使用 Homebrew 安装（仅限 macOS）如果你已经安装了 Homebrew（macOS 的包管理器），也可以：brew install claude-code3.2 Windows 安装步骤打开 PowerShell（建议以管理员身份运行），执行：npm install -g @anthropic-ai/claude-code[scode type="yellow" size="simple"]⚠️ 如果遇到类似 "无法加载文件...因为在此系统上禁止运行脚本" 的错误，先执行以下命令（允许本地运行脚本，安全无风险）：Set-ExecutionPolicy -Scope CurrentUser RemoteSigned然后再次尝试上面的 npm 安装命令。[/scode]3.3 验证安装安装完成后，在终端输入：claude --version如果能显示出版本号（例如 2.1.159 (Claude Code)），说明安装成功。[scode type="red" size="small"]安装成功后，先不要立即启动！[/scode]四、避开登录，接入 DeepSeek 或其他大模型 API4.1 原理说明Claude Code CLI 支持通过 ANTHROPIC_BASE_URL 环境变量自定义 API 地址。只要对接一个兼容 OpenAI/Anthropic 接口格式的 API 服务，就可以替换掉官方模型，不再需要 Anthropic 账号。通俗理解：原本 Claude Code 默认找的是"Anthropic 家的 API"，我们把地址改成"DeepSeek 家的 API"，它就去 DeepSeek 那里请求 AI 能力了。4.2 获取 DeepSeek API Key（免费注册）打开浏览器，访问 https://platform.deepseek.com点击右上角 "Sign Up" 注册账号（支持国内邮箱）登录后，进入左侧菜单 "API Keys"点击 "Create API Key"，输入名称（例如 claude-code），点击创建复制并保存好这个 Key（关闭弹窗后就看不到了，请务必保存到本地）[scode type="green" size="small"]💡 DeepSeek 可以先充值体验效果。[/scode]4.3 方式一：临时代理（推荐首次测试）每次启动终端时，先设置环境变量再运行：macOS / Linux：export ANTHROPIC_BASE_URL="https://api.deepseek.com/v1" export ANTHROPIC_API_KEY="sk-你的DeepSeek API密钥" claudeWindows（PowerShell）：$env:ANTHROPIC_BASE_URL="https://api.deepseek.com/v1" $env:ANTHROPIC_API_KEY="sk-你的DeepSeek API密钥" claude如果终端关闭，下次需要重新设置。适合先测试是否能用。4.4 方式二：配置文件持久化（推荐日常使用）创建配置文件，配置一次永久生效。macOS / Linux：# 创建配置文件目录 mkdir -p ~/.claude # 创建配置文件 cat > ~/.claude/settings.json << 'EOF' { "apiBaseUrl": "https://api.deepseek.com/v1", "apiKey": "sk-你的DeepSeek API密钥" } EOFWindows（PowerShell）：# 创建配置文件目录 New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.claude" # 创建配置文件 @' { "env": { "ANTHROPIC_BASE_URL": "https://api.deepseek.com/anthropic", "ANTHROPIC_MODEL": "deepseek-v4-pro[1m]", "ANTHROPIC_AUTH_TOKEN": "sk-xxxxxx你的密钥", "ANTHROPIC_DEFAULT_OPUS_MODEL": "deepseek-v4-pro[1m]", "ANTHROPIC_DEFAULT_SONNET_MODEL": "deepseek-v4-pro[1m]", "ANTHROPIC_DEFAULT_HAIKU_MODEL": "deepseek-v4-flash[1m]", "CLAUDE_CODE_SUBAGENT_MODEL": "deepseek-v4-flash[1m]", "CLAUDE_CODE_EFFORT_LEVEL": "max" }, "model": "haiku", "language": "中文,Chinese,简体中文", "theme": "auto" } '@ | Out-File -FilePath "$env:USERPROFILE\.claude\settings.json" -Encoding utf8配置好后，直接运行 claude 即可，不再需要每次手动设置环境变量。4.5 验证配置是否生效运行如下命令，检查是否报错：claude --version如果没有错误提示，说明配置文件加载成功。4.6 其他可选模型除了 DeepSeek，你也可以接入其他兼容 OpenAI 接口格式的服务，将上面配置中的 apiBaseUrl 和 apiKey 替换即可：服务商API Base URL说明DeepSeekhttps://api.deepseek.com/v1性价比高，速度快，推荐首选阿里通义https://dashscope.aliyuncs.com/compatible-mode/v1需开通通义千问 API智谱 GLMhttps://open.bigmodel.cn/api/paas/v4需开通智谱开放平台Ollama（本地运行）http://localhost:11434/v1完全本地运行，无需联网[scode type="yellow" size="simple"]⚠️ 重要提示： Claude Code 原生针对 Claude 模型做了很多深度优化（Tool Use 机制、超长上下文窗口、系统提示词等）。切换到其他模型后，部分高级功能可能不能完全正常工作。目前社区反馈中，DeepSeek 是兼容性最好的选择，基本能覆盖日常代码编写和审查的需求。[/scode]五、运行 Claude Code CLI5.1 首次运行在终端中直接输入：claude正常情况下，应该是可以直接进入对话界面，如果出现其他问题，可以将提示文本复制，然后打开deepseek对话，将问题发送给deepseek，获取对应的解决方案。六、常用命令与实战技巧6.1 claude — 启动交互式对话最基础的用法，进入对话界面。然后可以直接用自然语言提需求：> 帮我写一个 Python 脚本，读取当前目录下所有 CSV 文件并合并为一个Claude Code 会自动理解上下文，生成代码并执行。6.2 claude -p "你的问题" — 单次问答模式适合快速查询，不进入交互界面，执行完后直接退出终端：claude -p "git 如何撤销最后一次 commit？"该命令也可以配合管道使用，将其他命令的输出传给它处理：cat main.py | claude -p "帮我 review 这段代码，指出潜在问题"6.3 claude -f 文件路径 — 处理指定文件直接让 Claude Code 读取并处理某个文件，适合一键修复或分析：claude -f index.js -p "给这个文件添加 TypeScript 类型注解"6.4 claude --model — 指定模型如果你在配置中同时对接了多个模型，可以用这个参数切换：claude --model deepseek-chat对于其他 API 服务，填入对应的模型名称（例如通义千问的 qwen-plus）。6.5 claude --resume — 恢复上次会话如果上次对话因意外中断（终端关闭、断网、电脑休眠等）而退出，可以用此命令恢复：claude --resume对话上下文和历史都不会丢失，非常实用。6.6 claude --help — 查看所有命令和参数记不清参数时随时查看：claude --help会列出所有可用的 flag（命令行参数）和使用示例。6.7 交互模式下的实用快捷键在 claude 交互模式下，可以像在 Shell 中使用快捷键：快捷键作用Ctrl + C取消当前输入 / 退出↑ / ↓浏览历史消息输入 /help查看交互模式帮助输入 /clear清空当前会话上下文Ctrl + L清屏七、常见问题排查Q1：安装时提示 EACCES: permission denied原因： macOS 对全局 npm 包的权限检查比较严格。解决： 不要使用 sudo，而是配置 npm 的全局路径：npm config set prefix ~/.npm-global echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc source ~/.zshrc # 重新尝试安装 npm install -g @anthropic-ai/claude-codeQ2：运行 claude 提示命令未找到原因： npm 全局安装路径没有加到系统的 PATH 环境变量中。解决： 向你的 Shell 配置文件中添加：echo 'export PATH=$(npm bin -g):$PATH' >> ~/.zshrc source ~/.zshrcQ3：运行后提示 Request failed with status 401（认证失败）原因： API Key 无效或配置错误。解决： 检查 ~/.claude/settings.json 中的 apiKey 字段是否正确，注意不要有多余空格。Q4：运行后提示 connect ETIMEDOUT原因： 无法连接到配置的 API 地址，可能是网络问题。解决： 先在终端中用 curl 测试 API 地址是否可达：curl -I https://api.deepseek.com/v1如果返回非 200 状态码，说明该 API 服务在你当前的网络环境中不可用，请更换为其他可选服务商。八、总结回顾一下今天操作的全流程：准备工作：安装 Node.js ≥ 18，验证 node --version安装：一行命令 npm install -g @anthropic-ai/claude-code配置国内接入：创建 ~/.claude/settings.json，写入 DeepSeek 的 API 地址和密钥运行：claude 启动交互式对话，claude -p "问题" 单次问答常用命令：--resume 恢复会话、--model 切换模型、--help 查看帮助Claude Code CLI 是一个非常强大的编程助手工具，尤其适合在终端中完成代码生成、代码审查、项目探索、问题排查等任务。配合 DeepSeek 等国产大模型 API，国内用户完全可以零门槛上手使用。[scode type="blue" size=""]💡 扩展阅读建议：如果想进一步了解 Claude Code 的官方文档，可以访问 https://docs.anthropic.com/en/docs/claude-code（需科学上网）如果想了解 DeepSeek 的更多模型能力，查阅 DeepSeek 官方文档在终端中随时输入 claude --help 查看所有可用功能[/scode]订阅与代充值推荐[post cid="1020" cover="" size=""/]
引言：打破操作系统壁垒在日常工作中，Linux和Windows系统共存已成为常态。作为CentOS用户，您可能需要访问Windows服务器上的共享文件资源。本文将详细介绍如何在CentOS系统中挂载Windows共享目录，实现跨平台文件共享的无缝体验。核心优势：无需第三方软件命令行与图形界面双方法支持永久挂载配置解决常见连接问题一、前期准备1.1 Windows端配置创建共享文件夹（右键 > 属性 > 共享）设置共享权限（添加用户并分配权限）获取关键信息：Windows主机IP地址（cmd中运行 ipconfig）共享名称（如 ShareFolder）用户名和密码1.2 防火墙设置在Linux访问局域网Windows系统中的共享目录，需要设置Windows服务器的防火墙。开放”ICMPv4”访问：打开防火墙设置在 Windows 上，打开“控制面板”。点击“系统和安全”。点击“Windows Defender 防火墙”。在左侧，点击“高级设置”。创建“允许ICMPv4”入站规则在“Windows Defender 防火墙高级安全”窗口中，选择“入站规则”。在右侧，点击“新建规则”。选择“自定义”，然后点击“下一步”。在“规则类型”中，选择“所有程序”，然后点击“下一步”。在“协议和端口”中，选择“ICMPv4”，然后点击“下一步”。在“作用域”中，选择“任何 IP 地址”，然后点击“下一步”。（考虑主机访问安全，建议此处只允许放行Linux对应的IP地址）在“操作”中，选择“允许连接”，然后点击“下一步”。在“配置文件”中，选择适当的配置文件（域、私有、公共），然后点击“下一步”。给规则命名，例如“允许 ICMP”，然后点击“完成”。开放445访问端口重复上述防火墙操作步骤，相关配置修改如下：选择入站规则：在左侧，选择“入站规则”。新建规则：在右侧，点击“新建规则”。选择规则类型：选择“自定义”，然后点击“下一步”。选择程序：选择“所有程序”，然后点击“下一步”。选择协议和端口：在“协议类型”中，选择“TCP”。在“特定本地端口”中，输入 445（这是 SMB/CIFS 使用的端口），然后点击“下一步”。选择作用域：在“远程 IP 地址”中，选择“这些 IP 地址”，然后添加你的 Linux 机器的 IP 地址（例如 192.168.1.100）。如果你希望允许整个子网，可以输入 192.168.1.0/24。点击“下一步”。选择操作：选择“允许连接”，然后点击“下一步”。选择配置文件：选择适当的配置文件（域、私有、公共），然后点击“下一步”。命名规则：给规则命名，例如“允许 Linux 访问 SMB”，然后点击“完成”。在Windows上的防火墙相关配置已经结束，建议创建Windows共享访问账户，找到需要共享的目录执行创建共享操作。1.3 CentOS端准备确保网络连通性：ping 192.168.1.100 # 替换为Windows主机IP更新系统：sudo yum update -y二、安装必要软件包CentOS需要安装CIFS工具集来支持SMB协议：sudo yum install cifs-utils samba-client -y验证安装：rpm -q cifs-utils # 预期输出：cifs-utils-版本号三、命令行挂载方法3.1 创建本地挂载点sudo mkdir /mnt/win_share3.2 临时挂载共享目录sudo mount -t cifs //192.168.1.100/ShareFolder /mnt/win_share \ -o username=windows_user,password=your_password参数说明：-t cifs：指定文件系统类型//192.168.1.100/ShareFolder：Windows共享路径/mnt/win_share：本地挂载点username/password：Windows凭据3.3 验证挂载df -hT | grep cifs # 输出应显示挂载的共享目录 ls /mnt/win_share # 查看共享文件四、图形界面挂载方法（适合桌面版CentOS）打开文件管理器在地址栏输入：smb://192.168.1.100/ShareFolder输入Windows用户名和密码点击"连接"按钮连接成功后：共享目录将出现在侧边栏支持拖放文件操作书签功能可保存常用共享五、高级配置与优化5.1 永久挂载（配置/etc/fstab）编辑fstab文件实现开机自动挂载：sudo nano /etc/fstab添加以下内容：//192.168.1.100/ShareFolder /mnt/win_share cifs \ username=windows_user,password=your_password,uid=1000,gid=1000,file_mode=0777,dir_mode=0777 0 0参数解析：uid/gid：指定用户/组ID（通过 id命令查看）file_mode/dir_mode：设置文件/目录权限0 0：不备份不检查应用配置：sudo mount -a # 测试fstab配置5.2 安全凭据存储创建凭据文件避免密码明文暴露：sudo nano /etc/samba/credentials内容：username=windows_user password=your_password设置严格权限：sudo chmod 600 /etc/samba/credentials在fstab中使用凭据文件：//192.168.1.100/ShareFolder /mnt/win_share cifs \ credentials=/etc/samba/credentials,uid=1000,gid=1000 0 0六、故障排除指南6.1 常见错误及解决方案错误1：挂载失败（权限不足）mount error(13): Permission denied解决方案：确认Windows共享权限检查用户名/密码是否正确在挂载命令中添加 sec=ntlm选项错误2：协议版本不匹配Server supports SMB version X, but supports only Y解决方案：指定SMB版本-o vers=2.1 # 或 vers=3.0错误3：SELinux阻止访问SELinux is preventing access...解决方案：sudo setsebool -P samba_enable_home_dirs on sudo restorecon -Rv /mnt/win_share6.2 连接测试工具查看可用共享：smbclient -L //192.168.1.100 -U windows_user手动连接测试：smbclient //192.168.1.100/ShareFolder -U windows_user七、最佳实践建议网络安全：使用专用网络而非公共网络共享定期更新Windows和CentOS系统考虑使用VPN进行远程访问性能优化：-o cache=strict,rsize=65536,wsize=65536增加读写缓存大小禁用不必要的文件属性备份策略：# 示例备份命令 rsync -avz /mnt/win_share/ /backup/windows_share/定期同步重要数据使用cron设置自动化备份结论：无缝跨平台协作通过本指南，您已掌握在CentOS中访问Windows共享资源的多种方法。无论是命令行还是图形界面，临时访问还是永久挂载，都能满足不同场景的需求。跨平台文件共享不再是技术障碍，而是提高工作效率的桥梁。技术演进提示：随着SMB 3.1.1协议的普及，未来可探索更安全的加密传输方式，如AES-128-GCM加密，进一步提升数据传输安全性。如果在实践过程中遇到任何问题，欢迎在评论区留言讨论！
基于C#和MailKit构建企业级邮件客户端的实战指南
一、场景价值与工具选型1.1 企业邮件系统需求自动化处理工单邮件系统监控报警通知批量发送业务报表邮件数据归档分析1.2 为什么选择MailKit？🔐 全面支持SSL/TLS加密📦 完善的MIME消息处理⚡ 真正的异步IO实现📈 活跃的开源社区支持二、快速搭建开发环境2.1 创建项目与依赖安装# 创建控制台项目 dotnet new console -n EmailClient # 添加NuGet包 dotnet add package MailKit dotnet add package MimeKit2.2 配置邮箱连接参数public class EmailConfig { // 腾讯企业邮箱示例 public const string ImapServer = "imap.exmail.qq.com"; public const int ImapPort = 993; public const string SmtpServer = "smtp.exmail.qq.com"; public const int SmtpPort = 465; // 实际项目建议使用配置文件或密钥管理服务 public const string Username = "your@company.com"; public const string Password = "your_auth_code"; }三、核心功能实现详解3.1 未读邮件处理模块public void ProcessUnreadEmails() { using var client = new ImapClient(); // 建立安全连接 client.Connect(EmailConfig.ImapServer, EmailConfig.ImapPort, SecureSocketOptions.SslOnConnect); client.Authenticate(EmailConfig.Username, EmailConfig.Password); var inbox = client.Inbox; inbox.Open(FolderAccess.ReadWrite); // 高效搜索未读邮件 var uids = inbox.Search(SearchQuery.NotSeen); foreach (var uid in uids) { var message = inbox.GetMessage(uid); ProcessMessage(message); // 标记为已读（符合企业合规要求） inbox.AddFlags(uid, MessageFlags.Seen, true); } } private void ProcessMessage(MimeMessage message) { Console.WriteLine($"\n📨 收到新邮件 [{message.Date}]"); Console.WriteLine($"主题：{message.Subject}"); Console.WriteLine($"发件人：{message.From}"); // 智能解析正文内容 var textPart = message.TextBody; var htmlPart = message.HtmlBody; Console.WriteLine($"内容预览：{textPart?.Truncate(100)}"); // 安全保存附件 SaveAttachments(message.Attachments); } /// /// 安全保存邮件附件 /// /// 附件集合 private void SaveAttachments(IEnumerable<MimeEntity> attachments) { // 创建附件存储目录 var attachmentDir = Path.Combine(Directory.GetCurrentDirectory(), "Attachments"); Directory.CreateDirectory(attachmentDir); int index = 1; foreach (var attachment in attachments) { try { string fileName; if (attachment is MessagePart rfc822) { // 处理邮件型附件（.eml） fileName = $"forward_{DateTime.Now:yyyyMMddHHmmss}_{index}.eml"; using var stream = File.Create(Path.Combine(attachmentDir, fileName)); rfc822.Message.WriteTo(stream); } else if (attachment is MimePart part) { // 获取安全文件名 fileName = SanitizeFileName(part.FileName ?? $"unnamed_{index}.bin"); // 保存普通附件 using var stream = File.Create(Path.Combine(attachmentDir, fileName)); part.Content.DecodeTo(stream); } else { Console.WriteLine("⚠️ 未知附件类型"); continue; } Console.WriteLine($"📎 保存附件：{fileName}"); index++; } catch (Exception ex) { Console.WriteLine($"❗ 附件保存失败：{ex.Message}"); } } } /// /// 清理非法文件名字符 /// private string SanitizeFileName(string fileName) { var invalidChars = Path.GetInvalidFileNameChars(); return new string(fileName .Where(c => !invalidChars.Contains(c)) .ToArray()) .Replace(" ", "_"); // 替换空格为下划线 }关键技术点：使用 SearchQuery.NotSeen精准定位未读邮件通过 FolderAccess.ReadWrite实现已读标记自动处理多部分MIME消息体附件处理最佳实践路径安全：// 使用Path组合防止路径注入 var safePath = Path.Combine(attachmentDir, fileName);大文件处理：// 使用文件流分块读取 using var fs = new FileStream(path, FileMode.Create, FileAccess.Write); await part.Content.DecodeToAsync(fs);类型过滤：// 限制可接收的附件类型 var allowedTypes = new[] { "application/pdf", "image/png" }; if (!allowedTypes.Contains(part.ContentType.MimeType)) { Console.WriteLine("🚫 禁止的文件类型"); continue; }病毒扫描：// 调用杀毒软件接口（示例使用Windows Defender） var scanResult = Process.Start("MpCmdRun.exe", $"-Scan -ScanType 3 -File \"{filePath}\""); if (scanResult.ExitCode != 0) { File.Delete(filePath); }3.2 智能邮件发送模块public async Task SendEmailAsync() { var message = new MimeMessage(); message.From.Add(new MailboxAddress("系统通知", EmailConfig.Username)); // 支持多种分隔符的收件人输入 Console.Write("收件人（多个用逗号分隔）："); var recipients = Console.ReadLine()? .Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); message.To.AddRange(recipients.Select(MailboxAddress.Parse)); // 构建富文本内容 Console.Write("邮件主题："); message.Subject = Console.ReadLine(); var builder = new BodyBuilder(); Console.Write("HTML内容："); builder.HtmlBody = Console.ReadLine(); // 处理混合附件 Console.Write("附件路径（支持本地/网络地址）："); await ProcessAttachmentsAsync(builder, Console.ReadLine()); message.Body = builder.ToMessageBody(); using var client = new SmtpClient(); await client.ConnectAsync(EmailConfig.SmtpServer, EmailConfig.SmtpPort, SecureSocketOptions.SslOnConnect); await client.AuthenticateAsync(EmailConfig.Username, EmailConfig.Password); await client.SendAsync(message); }附件处理关键技术：private async Task ProcessAttachmentsAsync(BodyBuilder builder, string input) { foreach (var item in input.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)) { var path = item.Trim(); if (Uri.IsWellFormedUriString(path, UriKind.Absolute)) { await AddWebAttachmentAsync(builder, new Uri(path)); } else if (File.Exists(path)) { builder.Attachments.Add(path); } } } private async Task AddWebAttachmentAsync(BodyBuilder builder, Uri uri) { try { using var httpClient = new HttpClient(); var response = await httpClient.GetAsync(uri); var fileName = Path.GetFileName(uri.LocalPath) ?? "attachment.bin"; builder.Attachments.Add(fileName, await response.Content.ReadAsStreamAsync()); } catch (Exception ex) { Console.WriteLine($"⚠️ 附件下载失败：{uri} \n错误：{ex.Message}"); } }四、企业级最佳实践4.1 安全防护方案// 在Program初始化时添加 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, errors) => { // 生产环境应验证证书指纹 return errors == SslPolicyErrors.None; };4.2 性能优化策略使用 ObjectPool管理SMTP/IMAP连接对大型附件启用分块传输异步处理CPU密集型操作4.3 可观测性设计// 在客户端初始化时添加 client.Connected += (s, e) => Logger.LogInformation($"已连接 {e.Host}:{e.Port}"); client.Disconnected += (s, e) => Logger.LogWarning($"连接断开：{(e.IsRequested ? "正常" : "异常")}");五、完整控制台实现using System.Net; using MailKit.Net.Imap; using MailKit.Net.Smtp; using MailKit.Search; using MailKit.Security; using MimeKit; namespace EnterpriseEmailClient; class Program { static async Task Main(string[] args) { Console.Title = "企业邮件客户端 v1.0"; Console.OutputEncoding = System.Text.Encoding.UTF8; try { Console.WriteLine("=== 企业邮件管理系统 ==="); Console.WriteLine("1. 收取未读邮件"); Console.WriteLine("2. 发送邮件"); Console.WriteLine("======================="); Console.Write("请选择操作："); var choice = Console.ReadLine(); if (choice == "1") { ProcessUnreadEmails(); } else if (choice == "2") { await SendEmailAsync(); } else { Console.WriteLine("无效操作！"); } } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"操作失败：{ex.Message}"); Console.ResetColor(); } finally { Console.WriteLine("\n按任意键退出..."); Console.ReadKey(); } } // 以下是之前提到的 ProcessUnreadEmails() 和 SendEmailAsync() 方法 // [此处插入3.1和3.2节的代码实现...] }关键实现解析异步主方法：static async Task Main(string[] args)使用C# 7.1+的异步Main方法特性需要在项目文件添加 <LangVersion>latest</LangVersion>异常处理增强：catch (AuthenticationException) { Console.WriteLine("认证失败，请检查用户名/密码"); } catch (SocketException) { Console.WriteLine("网络连接失败，请检查服务器配置"); }用户体验优化：// 显示彩色状态提示 Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("✓ 邮件收取完成"); Console.ResetColor();六、项目文件配置（.csproj）<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <LangVersion>latest</LangVersion> </PropertyGroup> <ItemGroup> <PackageReference Include="MailKit" Version="3.4.3" /> <PackageReference Include="MimeKit" Version="3.4.3" /> </ItemGroup> </Project>完整代码结构树EnterpriseEmailClient/ ├── Program.cs # 主入口/界面逻辑 ├── Services/ │ ├── EmailReceiver.cs # 邮件接收服务 │ └── EmailSender.cs # 邮件发送服务 ├── Models/ │ └── EmailConfig.cs # 配置模型 └── Utils/ └── FileHelper.cs # 附件处理工具七、扩展开发建议邮件智能分类：集成ML.NET实现邮件自动分类审计日志系统：记录所有邮件操作记录邮件撤回功能：实现Exchange撤回协议大文件分卷压缩：自动处理超大附件八、常见问题解答Q1：如何解决附件乱码问题？// 强制指定附件编码 var attachment = new MimePart("application", "octet-stream") { Content = new MimeContent(File.OpenRead(path)), ContentDisposition = new ContentDisposition(ContentDisposition.Attachment), ContentTransferEncoding = ContentEncoding.Base64, FileName = Encoding.UTF8.GetBytes(filename) };Q2：如何处理邮件发送超时？var client = new SmtpClient { Timeout = 30000, // 30秒超时 ServerCertificateValidationCallback = (s,c,h,e) => true };九、项目成果展示未读邮件数量：3 📨 收到新邮件 [2023-08-20 14:30:00] 主题：季度销售报告 发件人：Sales <sales@partner.com> 内容预览：本季度总销售额达到$1,200,000，同比... 已保存附件：Q3_Sales_Report.pdf ✅ 邮件发送成功！耗时：2.3s
基于Tesseract.js的智能手写文字识别工具开发
引言随着人工智能和机器学习技术的快速发展，文字识别（OCR）技术已经成为了许多应用场景中的核心功能。无论是从图像中提取文本，还是识别手写文字，OCR技术都在不断进步。本文将介绍如何使用Tesseract.js开发一个基于Web的智能手写文字识别工具，并分享一些开发过程中的技术细节。项目概述本项目是一个基于Tesseract.js的在线手写文字识别系统，用户可以在网页上通过鼠标或触摸屏手写文字，系统会自动识别并显示识别结果。该工具支持笔画粗细调整、自动识别、图像预处理等功能，适用于多种场景下的手写文字识别需求。技术栈Tesseract.js ：一个基于Tesseract OCR引擎的JavaScript库，支持在浏览器中进行文字识别。HTML5 Canvas ：用于绘制手写文字的画布。JavaScript ：处理用户交互、图像预处理和文字识别逻辑。实现细节1. 初始化Tesseract OCR引擎Tesseract.js是一个强大的OCR库，支持多种语言的文字识别。在项目中，我们首先需要初始化Tesseract引擎，并加载中文和英文的语言模型。async function initTesseract() { try { scheduler = Tesseract.createScheduler(); worker = await Tesseract.createWorker({ logger: m => console.log(m) }); // 加载中文和英文语言包 await worker.loadLanguage('chi_sim+eng'); await worker.initialize('chi_sim+eng'); // 设置识别参数 await worker.setParameters({ tessedit_char_whitelist: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ你我他的是在有和人这中大为上个国我的时要出会可也得里说之用年行家方后作成开面而于经', tessedit_pageseg_mode: '6', // 假设文本是统一块 }); scheduler.addWorker(worker); console.log('Tesseract 初始化完成'); } catch (error) { console.error('Tesseract 初始化失败:', error); } }2. 画布绘制与交互用户可以通过鼠标或触摸屏在HTML5 Canvas上绘制手写文字。我们通过监听鼠标和触摸事件来捕获用户的绘制动作，并将绘制的笔画存储在一个数组中，以便后续的重绘和识别。function startDrawing(e) { isDrawing = true; const rect = canvas.getBoundingClientRect(); [lastX, lastY] = [ e.clientX - rect.left, e.clientY - rect.top ]; currentStroke = [{x: lastX, y: lastY}]; // 清除之前的识别计时器 if (recognizeTimer) { clearTimeout(recognizeTimer); recognizeTimer = null; } } function draw(e) { if (!isDrawing) return; const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; ctx.beginPath(); ctx.moveTo(lastX, lastY); ctx.lineTo(x, y); ctx.stroke(); currentStroke.push({x: x, y: y}); [lastX, lastY] = [x, y]; } function stopDrawing() { if (isDrawing) { isDrawing = false; strokes.push(currentStroke); currentStroke = []; scheduleRecognition(); } }3. 自动识别与图像预处理为了提高识别准确率，我们提供了自动识别功能。当用户停止书写1.5秒后，系统会自动触发文字识别。此外，用户还可以选择是否对图像进行预处理，如二值化处理，以增强识别效果。function scheduleRecognition() { if (!document.getElementById('autoRecognize').checked) return; if (recognizeTimer) { clearTimeout(recognizeTimer); } recognizeTimer = setTimeout(() => { recognizeText(); }, 1500); // 1.5秒后自动识别 } function preprocessImage(imageData) { const canvas2 = document.createElement('canvas'); canvas2.width = imageData.width; canvas2.height = imageData.height; const ctx2 = canvas2.getContext('2d'); ctx2.putImageData(imageData, 0, 0); const data = ctx2.getImageData(0, 0, canvas2.width, canvas2.height); const pixels = data.data; // 二值化处理 for (let i = 0; i < pixels.length; i += 4) { const gray = (pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3; const value = gray > 128 ? 255 : 0; pixels[i] = pixels[i + 1] = pixels[i + 2] = value; } ctx2.putImageData(data, 0, 0); return canvas2.toDataURL('image/png'); }4. 文字识别与结果显示当用户完成书写后，系统会将Canvas中的图像数据传递给Tesseract.js进行识别，并将识别结果显示在页面上。async function recognizeText() { if (!scheduler || !worker) { console.log('Tesseract未初始化'); return; } const loading = document.getElementById('loading'); const result = document.getElementById('result'); loading.style.display = 'block'; result.textContent = '正在识别中...'; try { let imageData; if (document.getElementById('preprocess').checked) { imageData = preprocessImage(ctx.getImageData(0, 0, canvas.width, canvas.height)); } else { imageData = canvas.toDataURL('image/png'); } const { data: { text } } = await scheduler.addJob('recognize', imageData); result.textContent = `识别结果: ${text.trim()}`; } catch (error) { console.error(error); result.textContent = '识别失败: ' + error.message; } finally { loading.style.display = 'none'; } }总结通过本项目，我们实现了一个基于Tesseract.js的智能手写文字识别工具。该工具不仅支持手写文字的实时识别，还提供了图像预处理、自动识别等功能，能够有效提高识别准确率。未来，我们可以进一步优化识别算法，增加更多语言支持，并将其应用于更多实际场景中。完整代码： 智能手写文字识别 智能手写文字识别 笔画粗细: 8 预处理: 增强对比度 自动识别(停笔1.5秒后) 清除 撤销 正在识别中... 准备就绪，请开始书写... © 2025 by Arvin-Hugh. All rights reserved.
迄今为止，程序员最佳输入法非Rime莫属
基本介绍很称心如意，很符合我的使用标准，无广告、无弹窗、不联网、词库完全自定义。界面风格全靠手码，千人千面，自己想要什么，自己画。关键还是跨平台的产品，不仅能在Windows上面跑，还能在MacOS和Linux上面运行，只是名字有点特殊，Windows叫：小狼毫，MacOS叫：鼠须管。如何安装和下载官网：Rime下载地址：在Github上面找到release面板即可下载 （下载0.16.3）安装：无脑操作，直接下一步下一步即可，无须特殊配置雾凇拼音GitHub地址：iDvel / rime-ice下载安装完成之后，强烈推荐安装的词库，符合大部分人的输入要求，下载完成后，进入“用户文件夹”，将下载的文件解压，然后点击“重新部署”，在点击“输入法设定“，选择自己需要的输入方案重头戏，如何配置皮肤进入用户文件夹后，找到“weasel.custome.yaml”文件，直接编辑，这里我编写了两套皮肤，是模仿苹果的，我觉得还挺好看，给大伙看看效果：如果还需要弄成其他的颜色，大家也可以大胆尝试。如果你们喜欢这个配色，可以直接将下面的代码复制到“weasel.custome.yaml”文件中，完成后需要点击重新部署才能使用。customization: distribution_code_name: Weasel distribution_version: 0.16.3 generator: "Weasel::UIStyleSettings" modified_time: "Fri Nov 15 09:28:21 2024" rime_version: 1.11.2 patch: preset_color_schemes: mac_blue_write: {author: arvin, back_color: 0xFFFFFFFF, border_color: 0xd2d2d2FF, candidate_format: "%c\u2005%@\u2005", candidate_back_color: 0xFFFFFFFF, candidate_text_color: 0x333333FF, corner_radius: 6, hilited_corner_radius: 6, color_format: rgba, comment_text_color: 0x5C5C5CFF, hilited_back_color: 0x315efb1a, hilited_candidate_back_color: 0x315efb1a, hilited_candidate_text_color: 0x0158ccFF, hilited_comment_text_color: 0x0158ccFF, hilited_label_color: 0x315efbFF, hilited_text_color: 0x0158ccFF, label_color: 0x333333FF, name: "苹果蓝白", shadow_color: 0x20212447, text_color: 0x333333FF} mac_blue_dark: {author: arvin, back_color: 0x181818, border_color: 0x0808080D, border_width: 0, candidate_format: "%c\u2005%@\u2005", candidate_back_color: 0x181818, candidate_text_color: 0xFFFFFF, color_format: abgr, comment_text_color: 0xFFFFFFFF, hilited_back_color: 0xFFc85c2f, hilited_candidate_back_color: 0xFFc85c2f, hilited_candidate_text_color: 0xFFFFFFFF, hilited_comment_text_color: 0xFFFFFF, hilited_label_color: 0xFFFFFF, hilited_text_color: 0xFFFFFF, label_color: 0xFFFFFF, name: "苹果黑", shadow_color: 0x080808DE, text_color: 0xFF333333} style: color_scheme: mac_blue_dark comment_font_face: "PingFang SC" comment_font_point: 11 display_tray_icon: true font_face: "Segoe UI Emoji, PingFang SC, Microsoft YaHei, SF Pro, Noto Color Emoji" font_point: 11 horizontal: true inline_preedit: true label_font_face: "PingFang SC" label_font_point: 10 label_format: "%s" layout: {align_type: bottom, border_width: 1, candidate_spacing: 16, corner_radius: 6, hilite_padding: 4, hilite_spacing: 3, margin_x: 7, margin_y: 7, max_height: 60, round_corner: 4, shadow_offset_x: 2, shadow_offset_y: 2, shadow_radius: 6, spacing: 5} mark_text: "" preedit_type: composition "style/color_scheme": mac_blue_write app_options: code.exe: {ascii_punct: true} #在VS Code中默认使用英文标点 hbuilderx.exe: {ascii_punct: true} #HBuilderX navicat.exe: {ascii_punct: true} devenv.exe: {ascii_punct: true} #VS 2022不喜欢，没关系，这里还有在线皮肤设计，你想怎么设计，就怎么设计：皮肤在线设计：润笔 、 RIME 西米 其他还有很多可以自定义的地方，比如自定义词典啥的，我这边也没有来得及多研究，总之挺好用，大家都用上！！
Java 格式化输出 printf 用法符号解释使用案例%s输出字符串System.out.printf("你好,我叫:%s",myName);%d输出整数System.out.printf("你好,今年:%d岁",age);%f输出小数System.out.printf("你好,今天一共消费:%f元",money);%n输出换行 %b输出布尔类型 %S输出字符串,英文大写 import java.util.Date; /** * 使用printf输出 * 关键技术点 * 使用java.io.PrintStream的printf方法实现C风格的输出 * printf 方法的第一个参数为输出的格式,第二个参数是可变长的,表示待输出的数据对象 */ public class Demo { public static void main(String[] args) { /*** 输出字符串 ***/ // %s表示输出字符串，也就是将后面的字符串替换模式中的%s System.out.printf("%s", new Integer(1212)); // %n表示换行 System.out.printf("%s%n", "end line"); // 还可以支持多个参数 System.out.printf("%s = %s%n", "Name", "Zhangsan"); // %S将字符串以大写形式输出 System.out.printf("%S = %s%n", "Name", "Zhangsan"); // 支持多个参数时，可以在%s之间插入变量编号，1$表示第一个字符串，3$表示第3个字符串 System.out.printf("%1$s = %3$s %2$s%n", "Name", "san", "Zhang"); /*** 输出boolean类型 ***/ System.out.printf("true = %b; false = ", true); System.out.printf("%b%n", false); /*** 输出整数类型***/ Integer iObj = 342; // %d表示将整数格式化为10进制整数 System.out.printf("%d; %d; %d%n", -500, 2343L, iObj); // %o表示将整数格式化为8进制整数 System.out.printf("%o; %o; %o%n", -500, 2343L, iObj); // %x表示将整数格式化为16进制整数 System.out.printf("%x; %x; %x%n", -500, 2343L, iObj); // %X表示将整数格式化为16进制整数，并且字母变成大写形式 System.out.printf("%X; %X; %X%n", -500, 2343L, iObj); /*** 输出浮点类型***/ Double dObj = 45.6d; // %e表示以科学技术法输出浮点数 System.out.printf("%e; %e; %e%n", -756.403f, 7464.232641d, dObj); // %E表示以科学技术法输出浮点数，并且为大写形式 System.out.printf("%E; %E; %E%n", -756.403f, 7464.232641d, dObj); // %f表示以十进制格式化输出浮点数 System.out.printf("%f; %f; %f%n", -756.403f, 7464.232641d, dObj); // 还可以限制小数点后的位数 System.out.printf("%.1f; %.3f; %f%n", -756.403f, 7464.232641d, dObj); /*** 输出日期类型***/ // %t表示格式化日期时间类型，%T是时间日期的大写形式，在%t之后用特定的字母表示不同的输出格式 Date date = new Date(); long dataL = date.getTime(); // 格式化年月日 // %t之后用y表示输出日期的年份（2位数的年，如99） // %t之后用m表示输出日期的月份，%t之后用d表示输出日期的日号 System.out.printf("%1$ty-%1$tm-%1$td; %2$ty-%2$tm-%2$td%n", date, dataL); // %t之后用Y表示输出日期的年份（4位数的年）， // %t之后用B表示输出日期的月份的完整名， %t之后用b表示输出日期的月份的简称 System.out.printf("%1$tY-%1$tB-%1$td; %2$tY-%2$tb-%2$td%n", date, dataL); // 以下是常见的日期组合 // %t之后用D表示以 "%tm/%td/%ty"格式化日期 System.out.printf("%1$tD%n", date); //%t之后用F表示以"%tY-%tm-%td"格式化日期 System.out.printf("%1$tF%n", date); /*** 输出时间类型***/ // 输出时分秒 // %t之后用H表示输出时间的时（24进制），%t之后用I表示输出时间的时（12进制）， // %t之后用M表示输出时间的分，%t之后用S表示输出时间的秒 System.out.printf("%1$tH:%1$tM:%1$tS; %2$tI:%2$tM:%2$tS%n", date, dataL); // %t之后用L表示输出时间的秒中的毫秒 System.out.printf("%1$tH:%1$tM:%1$tS %1$tL%n", date); // %t之后p表示输出时间的上午或下午信息 System.out.printf("%1$tH:%1$tM:%1$tS %1$tL %1$tp%n", date); // 以下是常见的时间组合 // %t之后用R表示以"%tH:%tM"格式化时间 System.out.printf("%1$tR%n", date); // %t之后用T表示以"%tH:%tM:%tS"格式化时间 System.out.printf("%1$tT%n", date); // %t之后用r表示以"%tI:%tM:%tS %Tp"格式化时间 System.out.printf("%1$tr%n", date); /*** 输出星期***/ // %t之后用A表示得到星期几的全称 System.out.printf("%1$tF %1$tA%n", date); // %t之后用a表示得到星期几的简称 System.out.printf("%1$tF %1$ta%n", date); // 输出时间日期的完整信息 System.out.printf("%1$tc%n", date); } } /** *printf方法中,格式为"%s"表示以字符串的形式输出第二个可变长参数的第一个参数值; *格式为"%n"表示换行;格式为"%S"表示将字符串以大写形式输出;在"%s"之间用"n$"表示 *输出可变长参数的第n个参数值.格式为"%b"表示以布尔值的形式输出第二个可变长参数 *的第一个参数值. */ /** * 格式为"%d"表示以十进制整数形式输出;"%o"表示以八进制形式输出;"%x"表示以十六进制 * 输出;"%X"表示以十六进制输出,并且将字母(A、B、C、D、E、F)换成大写.格式为"%e"表 * 以科学计数法输出浮点数;格式为"%E"表示以科学计数法输出浮点数,而且将e大写;格式为 * "%f"表示以十进制浮点数输出,在"%f"之间加上".n"表示输出时保留小数点后面n位. */ /** * 格式为"%t"表示输出时间日期类型."%t"之后用y表示输出日期的二位数的年份(如99)、用m * 表示输出日期的月份,用d表示输出日期的日号;"%t"之后用Y表示输出日期的四位数的年份 * (如1999)、用B表示输出日期的月份的完整名,用b表示输出日期的月份的简称."%t"之后用D * 表示以"%tm/%td/%ty"的格式输出日期、用F表示以"%tY-%tm-%td"的格式输出日期. */ /** * "%t"之后用H表示输出时间的时(24进制),用I表示输出时间的时(12进制),用M表示输出时间 * 分,用S表示输出时间的秒,用L表示输出时间的秒中的毫秒数、用 p 表示输出时间的是上午还是 * 下午."%t"之后用R表示以"%tH:%tM"的格式输出时间、用T表示以"%tH:%tM:%tS"的格式输出 * 时间、用r表示以"%tI:%tM:%tS %Tp"的格式输出时间. */ /** * "%t"之后用A表示输出日期的全称,用a表示输出日期的星期简称. */
AxWindowsMediaPlayer (Windows Media Play)控件的常用属性、方法及事件
概述AxWindowsMediaPlayer 对象是 Windows 媒体播放器 控件的根对象。本案例AxWindowsMediaPlayer控件取名: axPlay常用属性 [表-1]属性名数据类型描述或用法URLstring设置或获取媒体位置，本机或网络地址uiModestring设置或获取播放器的页面显示模式取值范围：Full, Mini, None, InvisibleplayStateWMPLib.WMPPlayState获取播放状态常见取值范围：wmppsStopped(停止)wmppsPaused(暂停)wmppsPlaying(正在播放)wmppsBuffering(正在缓冲)wmppsTransitioning(正在连接)wmppsReady(准备就绪)enableContextMenubool是否启用右键菜单fullScreenbool是否全屏显示Ctlcontrols-播放器控制属性，请查考[表-2]settings-播放器基本设置，请查考[表-3]currentMedia-播放器当前媒体，请查考[表-4]currentPlaylist-播放器当前播放列表，请查考[表-5]// 设置播放器的播放路径 axPlay.URL = @"C:\Demo\我爱的人.mp4"; // 设置播放器的页面显示模式 axPlay.uiMode = "Full"; // 获取播放器播放状态 var state = axPlay.playState; if(state == WMPLib.WMPPlayState.wmppsStopped) { // 播放器已停止播放 } // 禁用右键菜单 axPlay.enableContextMenu = false; // 开启全屏显示 axPlay.fullScreen = true;播放器基本控制属性常用方法 [表-2] [使用案例: axPlay.Ctlcontrols]方法名/属性名返回值类型描述或用法axPlay.Ctlcontrols.play()void控制播放器进行播放axPlay.Ctlcontrols.pause()void暂停axPlay.Ctlcontrols.stop()void停止axPlay.Ctlcontrols.next()void播放下一个媒体元素[需要提供播放列表]axPlay.Ctlcontrols.previous()void播放上一个媒体元素[需要提供播放列表]axPlay.Ctlcontrols.fastForward()void快进axPlay.Ctlcontrols.fastReverse()void快退axPlay.Ctlcontrols.currentPositiondouble获取或设置当前播放进度axPlay.Ctlcontrols.currentPositionStringstring获取当前播放进度,返回字符串格式。如“00:23”播放器基本控制属性常用方法 [表-3] [使用案例: axPlay.settings]方法名/属性名返回值类型描述或用法axPlay.settings.volumeint设置或获取音量，0-100axPlay.settings.autoStartbool是否自动播放axPlay.settings.mutebool是否开启静音axPlay.settings.playCountint播放次数播放器基本控制属性常用方法 [表-4] [使用案例: axPlay.currentMedia]方法名/属性名返回值类型描述或用法axPlay.currentMedia.durationdouble媒体总长度axPlay.currentMedia.durationStringstring媒体总长度，字符串格式。如“03:24”axPlay.currentMedia.getItemInfo(string bstrItemName)string获取当前媒体信息，bstrItemName参数填写字符串如下: "Title"=媒体标题"Author"=艺术家"Copyright"=版权信息"Description"=媒体内容描述"Duration"=持续时间（秒）"FileSize"=文件大小"FileType"=文件类型"sourceURL"=原始地址axPlay.currentMedia.setItemInfo(string bstrItemName, string bstrVal)void通过属性名设置媒体信息播放器基本控制属性常用方法 [表-5] [使用案例: axPlay.currentPlaylist]方法名/属性名返回值类型描述或用法axPlay.currentPlaylist.countint当前播放列表所包含媒体数axPlay.currentPlaylist.Item[int index]-获取或设置指定项目媒体信息，其子属性同wmp.currentMedia// 使当前播放器播放 axPlay.Ctlcontrols.play(); // 暂停 axPlay.Ctlcontrols.pause(); // 停止 axPlay.Ctlcontrols.stop(); // 播放下一个媒体 axPlay.Ctlcontrols.next(); // 获取或设置当前播放进度 double position = axPlay.Ctlcontrols.currentPosition; // 获取当前播放进度,返回字符串格式。如“00:23” string positions = axPlay.Ctlcontrols.currentPositionString; // 设置音量 axPlay.settings.volume = 50; // 设置自动播放 axPlay.settings.autoStart = true; // 开启静音 axPlay.settings.mute = true;[scode type="blue" size=""]如需了解更多，请参阅：Microsoft Ignite[/scode]
建立数据库新建数据库：GoodsInfo新建数据表：Category 【商品类别表】列名称数据类型是否为空说明CIDint否标识列，主键，商品类别编号CNamenvarchar(50)否商品类别名称新建数据表：Goods 【商品信息表】列名称数据类型是否为空说明GIDint否标识列，主键，商品编号GNamenvarchar(50)否商品名称CIDint否商品所属类别编号，外键Pricemoney否商品售价Brandnvarchar(20)否商品品牌名称Inventoryint否商品库存数据表建立结束后，请自行建立表与表之间的关系，并使用INSERT语句向每张表中至少添加3条测试数据。新建项目使用Visual Studio新建控制台应用程序：GoodsManagerSys，并创建数据库帮助类：DBHelper.cs，在数据库帮助类中完成实现对应方法。创建业务处理类：GoodsBusiness.cs，创建以下方法，请自行查看方法说明与注释。方法名返回值参数说明方法说明Menu()void/用于显示主菜单AddGoodsInfo()void/新增商品ShowGoodsCategory()void/显示商品分类列表ShowGoodsList()void/显示商品列表运行效果图为了让你们能够复制显示文本,项目运行效果图将以文本的形式提供----------------商品信息管理系统---------------- 1. 显示所有商品分类信息 2. 显示所有商品信息 3. 新增商品信息 4. 退出 ----------------------------------------------- 请选择操作菜单: 1 ----------------------------------------------- 商品分类编号 商品分类名称 ----------------------------------------------- 1 数码产品 2 家居用品 3 家用百货 4 休闲食品 ----------------------------------------------- 按任意键返回主菜单: x ----------------商品信息管理系统---------------- 1. 显示所有商品分类信息 2. 显示所有商品信息 3. 新增商品信息 4. 退出 ----------------------------------------------- 请选择操作菜单: 2 ----------------------------------------------- 商品编号 商品名称 品牌 售价 分类 库存 ----------------------------------------------- 1 华为Meta60 pro 华为 8999 数码产品 10 2 iPhone 15 pro 苹果 7999 数码产品 29 3 康师傅牛肉面 康师傅 5.5 休闲食品 9000 4 舒肤佳沐浴露 舒肤佳 49.9 家用百货 700 ----------------------------------------------- 按任意键返回主菜单: o ----------------商品信息管理系统---------------- 1. 显示所有商品分类信息 2. 显示所有商品信息 3. 新增商品信息 4. 退出 ----------------------------------------------- 请选择操作菜单: 3 您将要新增商品信息,请按要求依次输入 请输入商品名称: 山泉水 请输入商品品牌: 娃哈哈 请输入商品售价: 2.5 请输入商品入库库存: 200 请选择商品所属类别: ----------------------------------------------- 商品分类编号 商品分类名称 ----------------------------------------------- 1 数码产品 2 家居用品 3 家用百货 4 休闲食品 ----------------------------------------------- 请输入类别编号: 5 很抱歉,您输入的编号无效,请重新输入: 7 很抱歉,您输入的编号无效,请重新输入: 1 商品信息添加成功|失败,请按任意键返回主菜单: q ----------------商品信息管理系统---------------- 1. 显示所有商品分类信息 2. 显示所有商品信息 3. 新增商品信息 4. 退出 ----------------------------------------------- 请选择操作菜单: 4 谢谢您的使用,再见!运行与测试代码编写完成后，请自行测试。测试结束后，数据库无需分离，代码无需关闭，请联系专业课老师检查本次作业。
概述概述： ADO.NET是一组公开数据访问服务的类，可以对数据源进行连接，对数据进行增、删、改、查等操作。ADO.NET为创建分布式数据共享应用程序提供了一组发放的组件。特点： 与数据源断开连接后也可以使用数据ADO.NET核心组件DataSet（数据集）：独立于数据源的数据访问，DataSet是一个内存中的缓存，用于在应用程序中保存从数据库中检索的数据。它可以包含多个DataTable对象，关系和约束，可以方便地在应用程序中进行数据处理。.NET 数据提供程序[scode type="green" size="small"]1️⃣直接对数据源进行操作2️⃣连接数据源、执行命令和检索结果3️⃣实现数据操作和对数据的快速、只进只读访问[/scode].NET 数据提供程序中的4大核心对象[scode type="blue" size="small"]1️⃣Connection：用于开启程序和数据库之间的连接，它是连接数据库的关键组件，可以打开和关闭与数据库的连接。通过Connection对象，你可以指定数据库的位置、凭据、连接超时等参数。2️⃣Command：用于对数据库发出一些操作指令，它允许你执行SQL语句（例如SELECT、INSERT、UPDATE、DELETE等），并从数据库中检索数据或修改数据。Command对象也可以执行存储过程。3️⃣DataAdapter：在数据源和DataSet之间执行数据传输工作，DataAdapter是用于填充DataSet（数据集）和更新数据库的桥梁。它可以从数据库中检索数据，并将其填充到DataSet中的DataTable对象中。同样，它也可以从DataSet中获取更改，并将这些更改更新回数据库。4️⃣DataReader：DataReader是一种只进只读的数据访问方式。当你执行查询并希望逐行读取结果时，DataReader非常有用。它比DataSet更轻量级，对于大型数据集来说，性能更好，因为它不需要将整个结果集加载到内存中。[/scode]Connection连接对象语法：SqlConnection connection = new Sqlconnection(String ConnectionString);Connection对象常用属性和方法：属性🔨 / 方法📦说 明🔨 ConnectionString设置/获取应用程序连接数据库的连接字符串📦 void Open()用于打开与指定数据库的连接📦 void Close()关闭与数据库的连接使用案例演示：// 第一步: 定义链接字符串 private string constr constr = @"server=数据库服务引擎IP地址或主机名称;database=数据库名称;user=用户名;pwd=密码"; /* 数据库链接字符串拼接方式有很多种 * 例如: * Data Source=服务器名称或IP地址;Initial Catalog=数据库名;User Id=用户名;pwd=密码; * Data Source=服务器名称或IP地址;Initial Catalog=数据库名;Integrated Security=True; //Windows集成验证 */ // 第二步: 创建连接对象,此处演示案例为连接SQL Server数据库 SqlConnection connection = new Sqlconnection(constr); //在创建连接对象时,需要提供连接字符串 // 第三步: 打开或关闭连接对象 connection.Open(); //打开连接。如需关闭,请使用Close()方法[scode type="red" size="small"]⚠注意在.NET Core 框架下，不会自动添加System.Data和System.Data.SqlClient的引用，需要在菜单栏，选择"工具(T)" >"NuGet包管理器(N)";在“NuGget – 解决方案”窗口“浏览”选项卡的搜索框中输入“System.Data.SqlClient”关键字;点中搜索列表中匹配的条目，勾选项需要添加引用的项目，点击安装[/scode][scode type="green" size="small"]💬提示：在进行数据库连接或操作数据库时，请在代码中添加合理的try-catch-finally异常处理语句try{ //可能会出现异常的代码 }catch(Exception ex){ //出现异常后进行的处理代码 }finally{ //不管是否出现异常都需要执行的代码 }[/scode]Command命令对象功能:执行返回单条记录的SELECT语句，例如聚合函数SUM、AVG等执行返回具有多条记录的SELECT语句执行DML语句，例如修改、插入、删除记录等执行DDL语句，如创建表语法：SqlCommand command=new SqlCommand(String sql,SqlConnection conn);Command对象常用属性和方法：属性🔨 / 方法📦说 明🔨 ConnectionCommand对象使用的数据库连接🔨 CommandText要执行的SQL语句📦 SqlDataReader ExecuteReader()执行查询命令，返回DataReader对象📦 Object ExecuteScalar()执行查询返回单一值,例如执行COUNT(*)✔执行返回单个值的select语句,如聚合函数SUM、AVG等📦 int ExecuteNonQuery()用于执行非查询类操作， 返回的值是本次操作所影响的行数✔执行DML语句，如修改、插入、删除记录等演示案例-使用Command对象查找BookDB数据库用户表中是否存在指定用户：新建数据库帮助类DBHelper：using System; using System.Data.SqlClient; namespace Demo { /// /// 数据库帮助类 /// public class DBHelper { // 定义数据库连接字符串 private const string constr = @"server=.;database=BookDB;user=sa;pwd=123123"; /// /// 执行SQL语句,返回数据结果集中的第一行的第一列的值 /// /// 需要执行的SQL语句 /// <returns>返回数据结果集中的第一行的第一列的值,会返回NULL</returns> public object ExecuteScalar(string sql) { // 创建数据库连接对象并提供数据库连接字符串凭证 SqlConnection con = new SqlConnection(constr); // 创建命令对象,提供数据库连接对象以及需要执行的SQL语句 SqlCommand cmd = new SqlCommand(sql, con); // 使用异常处理 try { con.Open(); return cmd.ExecuteScalar(); } catch (Exception ex) { Console.WriteLine($"数据库访问异常,错误信息:{ex.Message}"); } finally { con.Close(); } return null; } } }测试类Program：using System; namespace Demo { class Program { static void Main(string[] args) { // 提示用户输入用户名与登录密码 Console.Write("请输入您的用户名:"); string name = Console.ReadLine(); Console.Write("请输入您的登录密码:"); string pwd = Console.ReadLine(); // 拼接SQL语句,判断该用户是否存在 string checkUserInfo = $"SELECT COUNT(0) FROM UserInfo WHERE Name = '{name}' AND Password = '{pwd}'"; // 创建DBHelper对象 DBHelper db = new DBHelper(); // 调用该方法 int res = Convert.ToInt32(db.ExecuteScalar(checkUserInfo)); // 判断执行结果 if (res == 1) { Console.WriteLine("用户登录成功!"); } else { Console.WriteLine("您输入的账号或密码不存在,请稍后再试!"); } } } }DataReader数据读取对象功能:从数据源中检索只读、只进的数据流每次读取一行数据DataReader对象常用属性和方法：属性🔨 / 方法📦说 明🔨 FieldCount获取当前行的列数🔨 HasRows属性获取一个值，该值指示SqlDataReader是否包含一行或多行,如果是则返回true,否则返回false;🔨 IsClosed判断当前对象是否已关闭。若值为true，则表示当前对象已关闭；否则，值为false📦 Read()前进到下一行记录。若读到一条记录，则返回true；否则，返回false📦 Close()关闭DataReader对象演示案例：// 调用DBHelper类中的查询一行的方法 ... SqlDataReader reader = db.ExecuteReader(sql); while (reader != null && reader.HasRows && reader.Read()){ //循环读取数据行 string name = reader["UserName"].ToString(); //...省略其他代码 } // 循环读取结束后,关闭读取器 if(reader != null) { reader.Close(); //关闭DataReader }DataAdapter数据适配器对象功能： 表示一组SQL命令和一个数据库连接，它们用于填充DataSet和更新数据源创建DataAdapter对象：//创建Connection对象 //... con.Open(); SqlDataAdapter adapter = new SqlDataAdapter("查询SQL语句", con);创建DataSet对象，调用DataAdapter对象提供的Fill()方法，将数据从数据源加载到DataSet中：// 创建数据集对象 DataSet ds=new DataSet(); // 填充数据集 adapter.Fill(ds);DataSet简介概述:是数据的脱机容器，是临时存储数据的仓库不包含数据库连接的概念(数据可以来自数据库也可以来自其他类型的文件)DataSet 由一组数据表组成,每个表又由数据列和数据行组成总结