C++利用SOCKET传送文件

C++利用SOCKET传送文件

/*server.h*/

#pragma comment(lib, "WS2_32")

#include <WinSock2.h>
#include <iostream>
//#include <stdio.h>
#include <assert.h>

#ifndef COMMONDEF_H
#define COMMONDEF_H

#define MAX_PACKET_SIZE   10240    // 数据包的最大长度,单位是sizeof(char)
#define MAXFILEDIRLENGTH 256     // 存放文件路径的最大长度
#define PORT     4096    // 端口号
#define SERVER_IP    "127.0.0.1" // server端的IP地址

// 各种消息的宏定义
#define INVALID_MSG      -1   // 无效的消息标识
#define MSG_FILENAME     1   // 文件的名称
#define MSG_FILELENGTH     2   // 传送文件的长度
#define MSG_CLIENT_READY    3   // 客户端准备接收文件
#define MSG_FILE      4   // 传送文件
#define MSG_SENDFILESUCCESS    5   // 传送文件成功
#define MSG_OPENFILE_ERROR    10   // 打开文件失败,可能是文件路径错误找不到文件等原因
#define MSG_FILEALREADYEXIT_ERROR 11   // 要保存的文件已经存在了

class CCSDef
{
public:
#pragma pack(1)      // 使结构体的数据按照1字节来对齐,省空间

// 消息头
struct TMSG_HEADER
{
   char    cMsgID;    // 消息标识

   TMSG_HEADER(char MsgID = INVALID_MSG)
    : cMsgID(MsgID)
   {
   }
};

// 请求传送的文件名
// 客户端传给服务器端的是全路径名称
// 服务器传回给客户端的是文件名
struct TMSG_FILENAME : public TMSG_HEADER
{
   char szFileName[256];   // 保存文件名的字符数组

   TMSG_FILENAME()
    : TMSG_HEADER(MSG_FILENAME)
   {
   }
};

// 传送文件长度
struct TMSG_FILELENGTH : public TMSG_HEADER
{
   long lLength;

   TMSG_FILELENGTH(long length)
    : TMSG_HEADER(MSG_FILELENGTH), lLength(length)
   {

   }
};

// Client端已经准备好了,要求Server端开始传送文件
struct TMSG_CLIENT_READY : public TMSG_HEADER
{
   TMSG_CLIENT_READY()
    : TMSG_HEADER(MSG_CLIENT_READY)
   {
   }
};

// 传送文件
struct TMSG_FILE : public TMSG_HEADER
{
   union     // 采用union保证了数据包的大小不大于MAX_PACKET_SIZE * sizeof(char)
   {
    char szBuff[MAX_PACKET_SIZE];
    struct
    {
     int nStart;
     int nSize;
     char szBuff[MAX_PACKET_SIZE - 2 * sizeof(int)];
    }tFile;
   };

   TMSG_FILE()
    : TMSG_HEADER(MSG_FILE)
   {

   }
};

// 传送文件成功
struct TMSG_SENDFILESUCCESS : public TMSG_HEADER
{
   TMSG_SENDFILESUCCESS()
    : TMSG_HEADER(MSG_SENDFILESUCCESS)
   {
   }
};

// 传送出错信息,包括:
// MSG_OPENFILE_ERROR:打开文件失败
// MSG_FILEALREADYEXIT_ERROR:要保存的文件已经存在了
struct TMSG_ERROR_MSG : public TMSG_HEADER
{
   TMSG_ERROR_MSG(char cErrorMsg)
    : TMSG_HEADER(cErrorMsg)
   {
   }
};

#pragma pack()
};

#endif

/*server.cpp*/

#include "server.h"

char g_szNewFileName[MAXFILEDIRLENGTH];
char g_szBuff[MAX_PACKET_SIZE + 1];
long g_lLength;
char* g_pBuff = NULL;

// 初始化socket库
bool InitSocket();
// 关闭socket库
bool CloseSocket();
// 解析消息进行相应的处理
bool ProcessMsg(SOCKET sClient);
// 监听Client的消息
void ListenToClient();
// 打开文件
bool OpenFile(CCSDef::TMSG_HEADER* pMsgHeader, SOCKET sClient);
// 传送文件
bool SendFile(SOCKET sClient);
// 读取文件进入缓冲区
bool ReadFile(SOCKET sClient);

int main()
{
InitSocket();
ListenToClient();
CloseSocket();

return 0;
}

void ListenToClient()
{
// 创建socket套接字
SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (SOCKET_ERROR == sListen)
{
   printf("Init Socket Error!\n");
   return;
}

// 绑定socket到一个本地地址
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
if (::bind(sListen, (LPSOCKADDR)&sin, sizeof(sockaddr_in)) == SOCKET_ERROR)
{
   printf("Bind Error!\n");
   return;
}

// 设置socket进入监听状态
if (::listen(sListen, 10) == SOCKET_ERROR)
{
   printf("Listen Error!\n");
   return;
}

printf("Listening To Client...\n");

// 循环接收client端的连接请求
sockaddr_in ClientAddr;
int nAddrLen = sizeof(sockaddr_in);
SOCKET sClient;

while (INVALID_SOCKET == (sClient = ::accept(sListen, (sockaddr*)&ClientAddr, &nAddrLen)))
{
}

while (true == ProcessMsg(sClient))
{
}

// 关闭同客户端的连接
::closesocket(sClient);

::closesocket(sListen);
}

bool InitSocket()
{
// 初始化socket dll
WSADATA wsaData;
WORD socketVersion = MAKEWORD(2, 2);
if (::WSAStartup(socketVersion, &wsaData) != 0)
{
   printf("Init socket dll error\n");
   return false;
}

return true;
}

bool CloseSocket()
{
// 释放winsock库
::WSACleanup();

if (NULL != g_pBuff)
{
   delete [] g_pBuff;
   g_pBuff = NULL;
}

return true;
}

bool ProcessMsg(SOCKET sClient)
{
int nRecv = ::recv(sClient, g_szBuff, MAX_PACKET_SIZE + 1, 0);
if (nRecv > 0)
{
   g_szBuff[nRecv] = '\0';
}

// 解析命令
CCSDef::TMSG_HEADER* pMsgHeader = (CCSDef::TMSG_HEADER*)g_szBuff;
switch (pMsgHeader->cMsgID)
{
case MSG_FILENAME:    // 文件名
   {
    OpenFile(pMsgHeader, sClient);
   }
   break;
case MSG_CLIENT_READY:   // 客户端准备好了,开始传送文件
   {
    SendFile(sClient);
   }
   break;
case MSG_SENDFILESUCCESS: // 传送文件成功
   {
    printf("Send File Success!\n");
    return false;
   }
   break;
case MSG_FILEALREADYEXIT_ERROR: // 要保存的文件已经存在了
   {
    printf("The file reay to send already exit!\n");
    return false;
   }
   break;
}

return true;
}

bool ReadFile(SOCKET sClient)
{
if (NULL != g_pBuff)
{
   return true;
}

// 打开文件
FILE *pFile;
if (NULL == (pFile = fopen(g_szNewFileName, "rb")))   // 打开文件失败
{
   printf("Cannot find the file, request the client input file name again\n");
   CCSDef::TMSG_ERROR_MSG tMsgErrorMsg(MSG_OPENFILE_ERROR);
   ::send(sClient, (char*)(&tMsgErrorMsg), sizeof(CCSDef::TMSG_ERROR_MSG), 0);
   return false;
}

// 把文件的长度传回到client去
fseek(pFile, 0, SEEK_END);
g_lLength = ftell(pFile);
printf("File Length = %d\n", g_lLength);
CCSDef::TMSG_FILELENGTH tMsgFileLength(g_lLength);
::send(sClient, (char*)(&tMsgFileLength), sizeof(CCSDef::TMSG_FILELENGTH), 0);

// 处理文件全路径名,把文件名分解出来
char szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szFname[_MAX_FNAME], szExt[_MAX_EXT];
_splitpath(g_szNewFileName, szDrive, szDir, szFname, szExt);
strcat(szFname,szExt);
CCSDef::TMSG_FILENAME tMsgFileName;
strcpy(tMsgFileName.szFileName, szFname);
printf("Send File Name: %s\n", tMsgFileName.szFileName);
::send(sClient, (char*)(&tMsgFileName), sizeof(CCSDef::TMSG_FILENAME), 0);

// 分配缓冲区读取文件内容
g_pBuff = new char[g_lLength + 1];
if (NULL == g_pBuff)
{
   return false;
}

fseek(pFile, 0, SEEK_SET);
fread(g_pBuff, sizeof(char), g_lLength, pFile);
g_pBuff[g_lLength] = '\0';
fclose(pFile);

return true;
}

// 打开文件
bool OpenFile(CCSDef::TMSG_HEADER* pMsgHeader, SOCKET sClient)
{
CCSDef::TMSG_FILENAME* pRequestFilenameMsg = (CCSDef::TMSG_FILENAME*)pMsgHeader;

// 对文件路径名进行一些处理
char *p1, *p2;
for (p1 = pRequestFilenameMsg->szFileName, p2 = g_szNewFileName;
   '\0' != *p1;
   ++p1, ++p2)
{
   if ('\n' != *p1)
   {
    *p2 = *p1;
   }
   if ('\\' == *p2)
   {
    *(++p2) = '\\';
   }
}
*p2 = '\0';

ReadFile(sClient);

return true;
}

// 传送文件
bool SendFile(SOCKET sClient)
{
if (NULL == g_pBuff)
{
   ReadFile(sClient);
}

int nPacketBufferSize = MAX_PACKET_SIZE - 2 * sizeof(int); // 每个数据包存放文件的buffer大小
// 如果文件的长度大于每个数据包所能传送的buffer长度那么就分块传送
for (int i = 0; i < g_lLength; i += nPacketBufferSize)
{  
   CCSDef::TMSG_FILE tMsgFile;
   tMsgFile.tFile.nStart = i;
   if (i + nPacketBufferSize + 1> g_lLength)
   {
    tMsgFile.tFile.nSize = g_lLength - i;
   }
   else
   {
    tMsgFile.tFile.nSize = nPacketBufferSize;
   }
   //printf("start = %d, size = %d\n", tMsgFile.tFile.nStart, tMsgFile.tFile.nSize);
   memcpy(tMsgFile.tFile.szBuff, g_pBuff + tMsgFile.tFile.nStart, tMsgFile.tFile.nSize);
   ::send(sClient, (char*)(&tMsgFile), sizeof(CCSDef::TMSG_FILE), 0);
   Sleep(0.5);
}

delete [] g_pBuff;
g_pBuff = NULL;

return true;
}

 

/*client.h同server.h*/

/*client.cpp*/

#include "client.h"

long g_lLength = 0;
char* g_pBuff = NULL;
char g_szFileName[MAXFILEDIRLENGTH];
char g_szBuff[MAX_PACKET_SIZE + 1];
SOCKET g_sClient;

// 初始化socket库
bool InitSocket();
// 关闭socket库
bool CloseSocket();
// 把用户输入的文件路径传送到server端
bool SendFileNameToServer();
// 与server端连接
bool ConectToServer();
// 打开文件失败
bool OpenFileError(CCSDef::TMSG_HEADER *pMsgHeader);
// 分配空间以便写入文件
bool AllocateMemoryForFile(CCSDef::TMSG_HEADER *pMsgHeader);
// 写入文件
bool WriteToFile(CCSDef::TMSG_HEADER *pMsgHeader);
// 处理server端传送过来的消息
bool ProcessMsg();

int main()
{
InitSocket();
ConectToServer();
CloseSocket();
return 0;
}

// 初始化socket库
bool InitSocket()
{
// 初始化socket dll
WSADATA wsaData;
WORD socketVersion = MAKEWORD(2, 2);
if (::WSAStartup(socketVersion, &wsaData) != 0)
{
   printf("Init socket dll error\n");
   exit(-1);
}

return true;
}

// 关闭socket库
bool CloseSocket()
{
// 关闭套接字
::closesocket(g_sClient);
// 释放winsock库
::WSACleanup();

return true;
}

// 与server端连接进行文件的传输
bool ConectToServer()
{
// 初始化socket套接字
if (SOCKET_ERROR == (g_sClient = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
{
   printf("Init Socket Error!\n");
   exit(-1);
}

sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(PORT);
servAddr.sin_addr.S_un.S_addr = ::inet_addr(SERVER_IP);
if (INVALID_SOCKET == (::connect(g_sClient, (sockaddr*)&servAddr, sizeof(sockaddr_in))))
{
   printf("Connect to Server Error!\n");
   exit(-1);
}

// 输入文件路径传输到server端
SendFileNameToServer();

// 接收server端传过来的信息,直到保存文件成功为止
while (true == ProcessMsg())
{
}

return true;
}

// 把用户输入的文件路径传送到server端
bool SendFileNameToServer()
{
char szFileName[MAXFILEDIRLENGTH];
printf("Input the File Directory: ");

fgets(szFileName, MAXFILEDIRLENGTH, stdin);

// 把文件路径发到server端
CCSDef::TMSG_FILENAME tMsgRequestFileName;
strcpy(tMsgRequestFileName.szFileName, szFileName);
if (SOCKET_ERROR == ::send(g_sClient, (char*)(&tMsgRequestFileName), sizeof(CCSDef::TMSG_FILENAME), 0))
{
   printf("Send File Name Error!\n");
   exit(-1);
}

return true;
}

// 处理server端传送过来的消息
bool ProcessMsg()
{
CCSDef::TMSG_HEADER *pMsgHeader;
int nRecv = ::recv(g_sClient, g_szBuff, MAX_PACKET_SIZE + 1, 0);

pMsgHeader = (CCSDef::TMSG_HEADER*)g_szBuff;

switch (pMsgHeader->cMsgID)
{
case MSG_OPENFILE_ERROR:   // 打开文件错误
   {
    OpenFileError(pMsgHeader);
   }
   break;
case MSG_FILELENGTH:    // 文件的长度
   {
    if (0 == g_lLength)
    {
     g_lLength = ((CCSDef::TMSG_FILELENGTH*)pMsgHeader)->lLength;
     printf("File Length: %d\n", g_lLength);
    }
   }
   break;
case MSG_FILENAME:     // 文件名
   {
    return AllocateMemoryForFile(pMsgHeader);
   }
   break;
case MSG_FILE:      // 传送文件,写入文件成功之后退出这个函数
   {
    if (WriteToFile(pMsgHeader))
    {
     return false;
    }
   }
   break;
}

return true;
}

// 打开文件失败
bool OpenFileError(CCSDef::TMSG_HEADER *pMsgHeader)
{
if (NULL != g_pBuff)
   return true;
assert(NULL != pMsgHeader);

printf("Cannot find file!Please input again!\n");

// 重新输入文件名称
SendFileNameToServer();

return true;
}

// 查找是否已经存在了要保存的文件,同时分配缓冲区保存文件
bool AllocateMemoryForFile(CCSDef::TMSG_HEADER *pMsgHeader)
{
assert(NULL != pMsgHeader);

if (NULL != g_pBuff)
{
   return true;
}

CCSDef::TMSG_FILENAME* pRequestFilenameMsg = (CCSDef::TMSG_FILENAME*)pMsgHeader;
printf("File Name: %s\n", pRequestFilenameMsg->szFileName);

// 把文件的路径设置为C盘根目录下
strcpy(g_szFileName, "c:\\");
strcat(g_szFileName, pRequestFilenameMsg->szFileName);

// 查找相同文件名的文件是否已经存在,如果存在报错退出
FILE* pFile;
if (NULL != (pFile = fopen(g_szFileName, "r")))
{
   // 文件已经存在,要求重新输入一个文件
   printf("The file already exist!\n");
   CCSDef::TMSG_ERROR_MSG tMsgErrorMsg(MSG_FILEALREADYEXIT_ERROR);
   ::send(g_sClient, (char*)(&tMsgErrorMsg), sizeof(CCSDef::TMSG_ERROR_MSG), 0);

   fclose(pFile);
   return false;
}

// 分配缓冲区开始接收文件,如果分配成功就给server端发送开始传送文件的要求
g_pBuff = new char[g_lLength + 1];
if (NULL != g_pBuff)
{
   memset(g_pBuff, '\0', g_lLength + 1);
   printf("Now ready to get the file %s!\n", pRequestFilenameMsg->szFileName);
   CCSDef::TMSG_CLIENT_READY tMsgClientReady;

   if (SOCKET_ERROR == ::send(g_sClient, (char*)(&tMsgClientReady), sizeof(CCSDef::TMSG_CLIENT_READY), 0))
   {
    printf("Send Error!\n");
    exit(-1);
   }
}
else
{
   printf("Alloc memory for file error!\n");
   exit(-1);
}

return true;
}

// 写入文件
bool WriteToFile(CCSDef::TMSG_HEADER *pMsgHeader)
{
assert(NULL != pMsgHeader);

CCSDef::TMSG_FILE* pMsgFile = (CCSDef::TMSG_FILE*)pMsgHeader;

int nStart = pMsgFile->tFile.nStart;
int nSize = pMsgFile->tFile.nSize;
memcpy(g_pBuff + nStart, pMsgFile->tFile.szBuff, nSize);
if (0 == nStart)
{
   printf("Saving file into buffer...\n");
}

memcpy(g_pBuff + nStart, pMsgFile->tFile.szBuff, nSize);
//printf("start = %d, size = %d\n", nStart, nSize);

// 如果已经保存到缓冲区完毕就写入文件
if (nStart + nSize >= g_lLength)
{
   printf("Writing to disk....\n");
   // 写入文件
   FILE* pFile;
   pFile = fopen(g_szFileName, "w+b");
   fwrite(g_pBuff, sizeof(char), g_lLength, pFile);

   delete [] g_pBuff;
   g_pBuff = NULL;
   fclose(pFile);

   // 保存文件成功传送消息给server退出server
   CCSDef::TMSG_SENDFILESUCCESS tMsgSendFileSuccess;
   while (SOCKET_ERROR == ::send(g_sClient, (char*)(&tMsgSendFileSuccess), sizeof(CCSDef::TMSG_SENDFILESUCCESS), 0))
   {
   }

   printf("Save the file %s success!\n", g_szFileName);

   return true;
}
else
{
   return false;
}
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/254332.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三种方式在CentOS 7搭建KVM虚拟化平台

KVM 全称是基于内核的虚拟机&#xff08;Kernel-based Virtual Machine&#xff09;&#xff0c;它是一个 Linux的一个内核模块&#xff0c;该内核模块使得 Linux变成了一个Hypervisor&#xff1a;它由 Quramnet开发&#xff0c;该公司于 2008年被 Red Hat 收购 KVM的整体结构&…

(五)EasyUI使用——datagrid数据表格

DataGrid以表格形式展示数据&#xff0c;并提供了丰富的选择、排序、分组和编辑数据的功能支持。DataGrid的设计用于缩短开发时间&#xff0c;并且使开发人员不需要具备特定的知识。它是轻量级的且功能丰富。单元格合并、多列标题、冻结列和页脚只是其中的一小部分功能。具体功…

拾取模型的原理及其在THREE.JS中的代码实现

1. Three.js中的拾取 1.1. 从模型转到屏幕上的过程说开 由于图形显示的基本单位是三角形&#xff0c;那就先从一个三角形从世界坐标转到屏幕坐标说起&#xff0c;例如三角形abc 乘以模型视图矩阵就进入了视点坐标系&#xff0c;其实就是相机所在的坐标系&#xff0c;如下图&am…

StringBuilder-C#字符串对象

博主写作不容易&#xff0c;孩子需要您鼓励 万水千山总是情 , 先点个赞行不行 在C# 中&#xff0c;string是引用类型&#xff0c;每次改变string类对象的值&#xff0c;即修改字符串变量对应的字符串&#xff0c;都需要在内存中为新的字符串重新分配空间。在默写特定的情况…

java 19 - 11 异常的注意事项

1 /*2 * 异常注意事项:3 * A:子类重写父类方法时&#xff0c;子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)4 * B:如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常5 * C:如果被重写的…

数组去重的各种方式对比

数组去重&#xff0c;是一个老生常谈的问题了&#xff0c;在各厂的面试中也会有所提及&#xff0c;接下来就来细数一下各种数组去重的方式吧&#xff1b; 对于以下各种方式都统一命名为 unique&#xff0c;公用代码如下&#xff1a; // 生成一个包含100000个[0,50000)随机数的数…

Linux平台Makefile文件的编写基础篇和GCC参数详解

问&#xff1a;gcc中的-I.是什么意思。。。。看到了有的是gcc -I. -I/usr/xxxxx..那个-I.是什么意思呢 最佳答案 答&#xff1a;-Ixxx 的意思是除了默认的头文件搜索路径(比如/usr/include等&#xff09;外&#xff0c;同时还在路径xxx下搜索需要被引用的头文件。 所以你的gcc …

旧知识打造新技术--AJAX学习总结

AJAX是将旧知识在新思想的容器内进行碰撞产生的新技术&#xff1a;推翻传统网页的设计技术。改善用户体验的技术。 学习AJAX之初写过一篇《与Ajax的初次谋面》。当中都仅仅是一些自己浅显的理解&#xff0c;这次就总结一下它在历史长河中的重要地位。 【全】 AJAX全称为Asnychr…

C#数组基本操作

文章目录简介数组排序和反转语法实例查找数组元素语法实例数组元素求和、最大值、最小值、平均值语法实例数组字符串相互转化语法实例在字符串中查找、删除字符数组元素语法实例博主写作不容易&#xff0c;孩子需要您鼓励 万水千山总是情 , 先点个赞行不行 简介 C#提供了许…

redis(一)--认识redis

Redis官网对redis的定义是&#xff1a;“Redis is an open source, BSD licensed, advanced key-value cache and store”&#xff0c;可以看出&#xff0c;Redis是一种键值系统&#xff0c;可以用来缓存或存储数据。Redis是“Remote Dictionary Server”&#xff08;远程字典服…

转:如何用gcc编译生成动态链接库*.so文件 动态库

转&#xff1a;如何编译.so动态库问&#xff1a;我源文件为main.c, x.c, y.c, z.c,头文件为x.h,y.h,z.h如何编译成.so动态库&#xff1f;编译器用gcc最好能给出详细参数解释&#xff0c;谢谢答&#xff1a;# 声称动代连接库&#xff0c;假设名称为libtest.sogcc x.c y.c z.c -f…

工业镜头的主要参数与选型

文章目录简介1、镜头的分类(1) 以镜头安装分类(2) 以摄像头镜头规格分类(3) 以镜头光圈分类(4) 以镜头的视场大小分类(5) 从镜头焦距上分2、选择镜头的技术依据(1) 镜头的成像尺寸(2) 镜头的分辨率(3) 镜头焦距与视野角度(4) 光圈或通光量3、变焦镜头&#xff08;zoom lens&…

SQLSEVER 中的那些键和约束

SQL Server中有五种约束类型&#xff0c;各自是 PRIMARY KEY约束、FOREIGN KEY约束、UNIQUE约束、DEFAULT约束、和CHECK约束。查看或者创建约束都要使用到 Microsoft SQL Server Managment Studio。1. PRIMARY KEY约束 在表中常有一列或多列的组合&#xff0c;其值能唯一标识表…

数据库 sqlite 进阶

http://www.cppblog.com/czy463/archive/2013/12/16/204816.html 董淳光 前序&#xff1a; Sqlite3 的确很好用。小巧、速度快。但是因为非微软的产品&#xff0c;帮助文档总觉得不够。这些天再次研究它&#xff0c;又有一些收获&#xff0c;这里把我对 sqlite3 的研究列出来&a…

形象的列举-C# 枚举

文章目录简介例子分析点拨博主写作不容易&#xff0c;孩子需要您鼓励 万水千山总是情 , 先点个赞行不行 简介 枚举类型用于声明一组命名常数。 定义枚举类型语法格式如下&#xff1a;enum 枚举数组名{枚举成员列表};例如&#xff1a; enum week{星期一&#xff0c;星期二…

Confluence 6 手动备份站点

2019独角兽企业重金招聘Python工程师标准>>> Confluence 被配置自动备份数据&#xff0c;使用压缩的 XML 格式。同时你也可以通过 Confluence 的 管理员控制台&#xff08;Administration Console&#xff09;手动进行备份。 你需要具有 System Administrator 权限才…

编写高质量的Makefile

分类&#xff1a; c/c研究 GNU&amp;LINUX2010-09-12 15:31163人阅读 评论(0)收藏举报源地址 &#xff1a;http://acm.hrbeu.edu.cn/forums/index.php?showtopic1827&st0&gopid8924&#entry8924 一、前言 回想自己的第一个Makefile&#xff0c;是这个样子的 …

第六篇:python基础之文件处理

第六篇&#xff1a;python基础之文件处理 阅读目录 一.文件处理流程二.基本操作2.1 文件操作基本流程初探2.2 文件编码2.3 文件打开模式2.4 文件内置函数flush2.5 文件内光标移动2.6 open函数详解2.7 上下文管理2.8 文件的修改一.文件处理流程 打开文件&#xff0c;得到文件句柄…

前端每日实战:56# 视频演示如何用纯 CSS 描述程序员的生活

效果预览 按下右侧的“点击预览”按钮可以在当前页面预览&#xff0c;点击链接可以全屏预览。 https://codepen.io/comehope/pen/YvYVvY 可交互视频 此视频是可以交互的&#xff0c;你可以随时暂停视频&#xff0c;编辑视频中的代码。 请用 chrome, safari, edge 打开观看。 ht…

从特殊到一般-C#中的类

文章目录类的概念类的定义实例例子分析类的成员数据成员属性成员方法成员静态成员博主写作不容易&#xff0c;孩子需要您鼓励 万水千山总是情 , 先点个赞行不行 类的概念 在日常生活中&#xff0c;类是对具有相同特性的一类是物的抽象。比如水果是一个类&#xff0c;它是对…