#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
// 用户结构体
typedef struct {
int id;
char username[50];
char password[50];
int role; // 0-普通用户 1-管理员
char register_date[20];
} User;
// 分类结构体
typedef struct {
int id;
char name[50];
int article_count;
} Category;
// 文章结构体
typedef struct {
int id;
char title[100];
char content[1024];
int author_id;
int category_id;
char publish_date[20];
int view_count;
} Article;
// 浏览记录结构体
typedef struct {
int user_id;
int article_id;
char view_time[20];
} ViewRecord;
// 文件路径常量
#define USER_FILE "users.dat"
#define CATEGORY_FILE "categories.dat"
#define ARTICLE_FILE "articles.dat"
#define VIEW_FILE "views.dat"
// 函数声明
int generate_user_id();
int generate_article_id();
int generate_category_id();
void get_current_time(char *time_str);
void list_categories();
void update_category_count(int category_id, int increment);
Article find_article_by_id(int article_id);
const char *get_category_name(int category_id);
void update_article_view_count(int article_id);
void record_view_history(int user_id, int article_id);
void browse_articles(User *user);
void manage_articles(User *user);
void manage_categories(User *user);
void generate_statistics();
int check_permission(User *user, int required_role);
void user_register();
User *user_login();
void publish_article(User *author);
void view_article(User *user, int article_id);
void delete_article(User *user);
void add_category();
void delete_category();
void modify_category();
// 主函数
int main() {
User *current_user = NULL;
int choice;
while (1) {
printf("\n===== 文章管理系统 =====\n");
if (current_user) {
printf("当前用户: %s (%s)\n",
current_user->username,
current_user->role ? "管理员" : "普通用户");
}
printf("1. 注册\n2. 登录\n3. 发布文章\n4. 浏览文章\n");
printf("5. 文章管理\n6. 分类管理\n7. 数据统计\n8. 退出\n");
printf("选择操作: ");
scanf("%d", &choice);
switch (choice) {
case 1:
user_register();
break;
case 2:
current_user = user_login();
break;
case 3:
if (current_user)
publish_article(current_user);
else
printf("请先登录!\n");
break;
case 4:
browse_articles(current_user);
break;
case 5:
manage_articles(current_user);
break;
case 6:
manage_categories(current_user);
break;
case 7:
generate_statistics();
break;
case 8:
if (current_user) free(current_user);
printf("系统已退出\n");
return 0;
default:
printf("无效选择!\n");
}
}
}
// 生成用户ID
int generate_user_id() {
FILE *fp = fopen(USER_FILE, "rb");
if (!fp) return 1; // 文件不存在,从1开始
User user;
int max_id = 0;
while (fread(&user, sizeof(User), 1, fp)) {
if (user.id > max_id) max_id = user.id;
}
fclose(fp);
return max_id + 1;
}
// 生成文章ID
int generate_article_id() {
FILE *fp = fopen(ARTICLE_FILE, "rb");
if (!fp) return 1; // 文件不存在,从1开始
Article article;
int max_id = 0;
while (fread(&article, sizeof(Article), 1, fp)) {
if (article.id > max_id) max_id = article.id;
}
fclose(fp);
return max_id + 1;
}
// 生成分类ID
int generate_category_id() {
FILE *fp = fopen(CATEGORY_FILE, "rb");
if (!fp) return 1; // 文件不存在,从1开始
Category category;
int max_id = 0;
while (fread(&category, sizeof(Category), 1, fp)) {
if (category.id > max_id) max_id = category.id;
}
fclose(fp);
return max_id + 1;
}
// 获取当前时间字符串
void get_current_time(char *time_str) {
time_t now = time(NULL);
struct tm *t = localtime(&now);
strftime(time_str, 20, "%Y-%m-%d %H:%M:%S", t);
}
// 列出所有分类
void list_categories() {
FILE *fp = fopen(CATEGORY_FILE, "rb");
if (!fp) {
printf("暂无分类\n");
return;
}
printf("\n===== 文章分类 =====\n");
Category category;
while (fread(&category, sizeof(Category), 1, fp)) {
printf("ID: %d | 名称: %s | 文章数: %d\n",
category.id, category.name, category.article_count);
}
fclose(fp);
}
// 更新分类文章计数
void update_category_count(int category_id, int increment) {
// 临时文件用于更新
FILE *fp = fopen(CATEGORY_FILE, "rb");
FILE *tmp = fopen("temp.dat", "wb");
if (!fp || !tmp) return;
Category category;
while (fread(&category, sizeof(Category), 1, fp)) {
if (category.id == category_id) {
category.article_count += increment;
}
fwrite(&category, sizeof(Category), 1, tmp);
}
fclose(fp);
fclose(tmp);
// 替换原文件
remove(CATEGORY_FILE);
rename("temp.dat", CATEGORY_FILE);
}
// 通过ID查找文章
Article find_article_by_id(int article_id) {
FILE *fp = fopen(ARTICLE_FILE, "rb");
Article article = {.id = -1}; // 默认返回无效文章
if (fp) {
while (fread(&article, sizeof(Article), 1, fp)) {
if (article.id == article_id) {
break;
}
}
fclose(fp);
}
return article;
}
// 获取分类名称
const char *get_category_name(int category_id) {
static char name[50] = "未知分类";
FILE *fp = fopen(CATEGORY_FILE, "rb");
if (fp) {
Category category;
while (fread(&category, sizeof(Category), 1, fp)) {
if (category.id == category_id) {
strcpy(name, category.name);
break;
}
}
fclose(fp);
}
return name;
}
// 更新文章浏览计数
void update_article_view_count(int article_id) {
// 临时文件用于更新
FILE *fp = fopen(ARTICLE_FILE, "rb");
FILE *tmp = fopen("temp.dat", "wb");
if (!fp || !tmp) return;
Article article;
while (fread(&article, sizeof(Article), 1, fp)) {
if (article.id == article_id) {
article.view_count++;
}
fwrite(&article, sizeof(Article), 1, tmp);
}
fclose(fp);
fclose(tmp);
// 替换原文件
remove(ARTICLE_FILE);
rename("temp.dat", ARTICLE_FILE);
}
// 记录浏览历史
void record_view_history(int user_id, int article_id) {
ViewRecord record;
record.user_id = user_id;
record.article_id = article_id;
get_current_time(record.view_time);
FILE *fp = fopen(VIEW_FILE, "ab");
if (fp) {
fwrite(&record, sizeof(ViewRecord), 1, fp);
fclose(fp);
}
}
// 浏览文章
void browse_articles(User *user) {
FILE *fp = fopen(ARTICLE_FILE, "rb");
if (!fp) {
printf("暂无文章\n");
return;
}
printf("\n===== 文章列表 =====\n");
Article article;
while (fread(&article, sizeof(Article), 1, fp)) {
printf("ID: %d | 标题: %s | 分类: %s | 作者ID: %d | 浏览量: %d\n",
article.id, article.title, get_category_name(article.category_id),
article.author_id, article.view_count);
}
fclose(fp);
int article_id;
printf("\n输入要查看的文章ID (0返回): ");
scanf("%d", &article_id);
if (article_id > 0) {
view_article(user, article_id);
}
}
// 文章管理
void manage_articles(User *user) {
if (!check_permission(user, 1)) {
printf("权限不足!需要管理员权限\n");
return;
}
int choice;
do {
printf("\n===== 文章管理 =====\n");
printf("1. 删除文章\n2. 返回\n选择操作: ");
scanf("%d", &choice);
switch (choice) {
case 1:
delete_article(user);
break;
case 2:
return;
default:
printf("无效选择!\n");
}
} while (choice != 2);
}
// 分类管理
void manage_categories(User *user) {
if (!check_permission(user, 1)) {
printf("权限不足!需要管理员权限\n");
return;
}
int choice;
do {
printf("\n===== 分类管理 =====\n");
printf("1. 添加分类\n2. 删除分类\n3. 修改分类\n4. 返回\n选择操作: ");
scanf("%d", &choice);
switch (choice) {
case 1:
add_category();
break;
case 2:
delete_category();
break;
case 3:
modify_category();
break;
case 4:
return;
default:
printf("无效选择!\n");
}
} while (choice != 4);
}
// 数据统计
void generate_statistics() {
// 用户统计
int user_count = 0, admin_count = 0;
FILE *user_fp = fopen(USER_FILE, "rb");
if (user_fp) {
User user;
while (fread(&user, sizeof(User), 1, user_fp)) {
user_count++;
if (user.role == 1) admin_count++;
}
fclose(user_fp);
}
// 文章统计
int article_count = 0, total_views = 0;
FILE *article_fp = fopen(ARTICLE_FILE, "rb");
if (article_fp) {
Article article;
while (fread(&article, sizeof(Article), 1, article_fp)) {
article_count++;
total_views += article.view_count;
}
fclose(article_fp);
}
// 分类统计
int category_count = 0;
FILE *category_fp = fopen(CATEGORY_FILE, "rb");
if (category_fp) {
Category category;
while (fread(&category, sizeof(Category), 1, category_fp)) {
category_count++;
}
fclose(category_fp);
}
printf("\n===== 系统统计信息 =====\n");
printf("用户总数: %d (管理员: %d)\n", user_count, admin_count);
printf("文章总数: %d\n", article_count);
printf("分类总数: %d\n", category_count);
printf("总浏览量: %d\n", total_views);
}
// 权限检查
int check_permission(User *user, int required_role) {
if (user == NULL) return 0; // 未登录
if (user->role >= required_role) return 1; // 权限足够
return 0; // 权限不足
}
// 用户注册
void user_register() {
User new_user;
printf("请输入用户名: ");
scanf("%s", new_user.username);
// 检查用户名是否已存在
FILE *check_fp = fopen(USER_FILE, "rb");
if (check_fp) {
User user;
while (fread(&user, sizeof(User), 1, check_fp)) {
if (strcmp(user.username, new_user.username) == 0) {
printf("用户名已存在!\n");
fclose(check_fp);
return;
}
}
fclose(check_fp);
}
printf("请输入密码: ");
scanf("%s", new_user.password);
// 生成用户ID和注册时间
new_user.id = generate_user_id();
get_current_time(new_user.register_date);
new_user.role = 0; // 默认普通用户
// 保存到文件
FILE *fp = fopen(USER_FILE, "ab");
if (fp) {
fwrite(&new_user, sizeof(User), 1, fp);
fclose(fp);
printf("注册成功!用户ID: %d\n", new_user.id);
} else {
printf("注册失败!\n");
}
}
// 用户登录
User *user_login() {
char username[50], password[50];
printf("用户名: ");
scanf("%s", username);
printf("密码: ");
scanf("%s", password);
FILE *fp = fopen(USER_FILE, "rb");
if (!fp) {
printf("用户数据库不存在!\n");
return NULL;
}
User user;
while (fread(&user, sizeof(User), 1, fp)) {
if (strcmp(user.username, username) == 0 &&
strcmp(user.password, password) == 0) {
fclose(fp);
User *logged_user = malloc(sizeof(User));
*logged_user = user;
printf("登录成功!欢迎 %s\n", username);
return logged_user;
}
}
fclose(fp);
printf("用户名或密码错误!\n");
return NULL;
}
// 发布文章
void publish_article(User *author) {
Article new_article;
printf("文章标题: ");
scanf(" %[^\n]", new_article.title); // 读取带空格的标题
printf("文章内容: ");
scanf(" %[^\n]", new_article.content);
// 设置文章信息
new_article.id = generate_article_id();
new_article.author_id = author->id;
new_article.view_count = 0;
get_current_time(new_article.publish_date);
// 选择分类
list_categories();
printf("选择分类ID: ");
scanf("%d", &new_article.category_id);
// 保存文章
FILE *fp = fopen(ARTICLE_FILE, "ab");
if (fp) {
fwrite(&new_article, sizeof(Article), 1, fp);
fclose(fp);
// 更新分类统计
update_category_count(new_article.category_id, 1);
printf("文章发布成功!ID: %d\n", new_article.id);
} else {
printf("文章发布失败!\n");
}
}
// 查看文章
void view_article(User *user, int article_id) {
// 查找文章
Article article = find_article_by_id(article_id);
if (article.id == -1) {
printf("文章不存在!\n");
return;
}
// 显示文章内容
printf("\n===== 文章详情 =====\n");
printf("标题: %s\n", article.title);
printf("分类: %s\n", get_category_name(article.category_id));
printf("发布时间: %s\n", article.publish_date);
printf("浏览数: %d\n\n", article.view_count + 1);
printf("内容:\n%s\n\n", article.content);
// 更新浏览计数
update_article_view_count(article_id);
// 记录浏览历史
if (user != NULL) {
record_view_history(user->id, article_id);
}
}
// 删除文章
void delete_article(User *user) {
if (!check_permission(user, 1)) {
printf("权限不足!需要管理员权限\n");
return;
}
int article_id;
printf("输入要删除的文章ID: ");
scanf("%d", &article_id);
// 查找文章获取分类ID
Article article = find_article_by_id(article_id);
if (article.id == -1) {
printf("文章不存在!\n");
return;
}
// 临时文件用于删除操作
FILE *fp = fopen(ARTICLE_FILE, "rb");
FILE *tmp = fopen("temp.dat", "wb");
if (!fp || !tmp) {
printf("操作失败!\n");
return;
}
Article current;
int found = 0;
while (fread(¤t, sizeof(Article), 1, fp)) {
if (current.id != article_id) {
fwrite(¤t, sizeof(Article), 1, tmp);
} else {
found = 1;
}
}
fclose(fp);
fclose(tmp);
if (found) {
// 替换原文件
remove(ARTICLE_FILE);
rename("temp.dat", ARTICLE_FILE);
// 更新分类文章计数
update_category_count(article.category_id, -1);
printf("文章 %d 已删除\n", article_id);
} else {
remove("temp.dat");
printf("文章不存在!\n");
}
}
// 添加分类
void add_category() {
Category new_category;
printf("输入分类名称: ");
scanf(" %[^\n]", new_category.name);
new_category.id = generate_category_id();
new_category.article_count = 0;
FILE *fp = fopen(CATEGORY_FILE, "ab");
if (fp) {
fwrite(&new_category, sizeof(Category), 1, fp);
fclose(fp);
printf("分类添加成功!ID: %d\n", new_category.id);
} else {
printf("添加失败!\n");
}
}
// 删除分类
void delete_category() {
int category_id;
printf("输入要删除的分类ID: ");
scanf("%d", &category_id);
// 检查分类是否存在
Category category;
int found = 0;
FILE *check_fp = fopen(CATEGORY_FILE, "rb");
if (check_fp) {
while (fread(&category, sizeof(Category), 1, check_fp)) {
if (category.id == category_id) {
found = 1;
break;
}
}
fclose(check_fp);
}
if (!found) {
printf("分类不存在!\n");
return;
}
if (category.article_count > 0) {
printf("该分类下有文章,不能删除!\n");
return;
}
// 删除操作
FILE *fp = fopen(CATEGORY_FILE, "rb");
FILE *tmp = fopen("temp.dat", "wb");
if (!fp || !tmp) {
printf("操作失败!\n");
return;
}
while (fread(&category, sizeof(Category), 1, fp)) {
if (category.id != category_id) {
fwrite(&category, sizeof(Category), 1, tmp);
}
}
fclose(fp);
fclose(tmp);
remove(CATEGORY_FILE);
rename("temp.dat", CATEGORY_FILE);
printf("分类 %d 已删除\n", category_id);
}
// 修改分类
void modify_category() {
int category_id;
printf("输入要修改的分类ID: ");
scanf("%d", &category_id);
// 查找分类
FILE *fp = fopen(CATEGORY_FILE, "rb+");
if (!fp) {
printf("分类数据库不存在!\n");
return;
}
Category category;
int found = 0;
long position = 0;
while (fread(&category, sizeof(Category), 1, fp)) {
if (category.id == category_id) {
found = 1;
break;
}
position = ftell(fp);
}
if (!found) {
printf("分类不存在!\n");
fclose(fp);
return;
}
printf("当前名称: %s\n", category.name);
printf("输入新名称: ");
scanf(" %[^\n]", category.name);
// 定位并更新
fseek(fp, position, SEEK_SET);
fwrite(&category, sizeof(Category), 1, fp);
fclose(fp);
printf("分类修改成功!\n");
}