python_PyQt5开发股票日数据更新工具

news2024/11/29 2:36:13

写在前面:

该工具更新的股票日数据来自优矿,为了把股票日数据在本地存储一份,这就面临需要定期更新的需求,为此开发了这个工具。

定期更新的股票日数据特征:

1 旧股票日数据(也就是上次更新的数据,假如说10天前更新的日数据)

2 那本次要更新的就是最近这10产生的股票日数据,这10天产生的股票日数据有两种

一种是10天前已经上市的股票,那这十天的日数据需要追加到旧股票日数据的后面

一种是这10天内新上市的股票,那就创建新的文件存储股票日数据

业务过程技术实现逻辑:

1 旧股票数据做什么处理?

==》计算出每个股票最后的日期,对于最后的日期距离现在很远的,说明是退市股票,不予理睬,对日期进行分组,取得股票最多的那个日期

2 上次数据更新时点到当前的时间区间新上市的股票如何计算?

==》从优矿中下载当前上市的所有股票代码,与旧股票数据进行比对,筛出在就股票中没有的股票代码即为新上市的股票

演示工具:

“选择【结果放置目录】” ==》由于处理过程中会产生中间文件,所以需要设置一个目录用来存放程序生成的文件 

“选择【未更新旧日数据目录】”==》就是上次更新的日数据存储的目录

“上传【当前最新股票列表文件】”==》从优矿中下载当前上市的股票列表,上传给工具,后面做比对筛出新上市的股票

“生成【未更新数据最后日期列表】”==》遍历旧日数据,取最后一条的日期,用以后面知道哪些股票要从哪个时间节点开始下载日数据

“筛出【要更新的股票列表】”==》两种,一种是非新上市的股票代码列表,一种是新上市的股票代码列表

“将合并股票日数据所在目录”==》从优矿中下载的未复权日数据所存储的目录

代码:

股票数据有五千多个,定期更新业务中多个步骤需要遍历,遍历的语法耗时较长,所以开发时用了多线程,耗时的业务都子线程中运行,避免界面卡死。

import datetime,os,shutil,sys
from threading import Thread
import pandas as pd
from PyQt5 import QtCore,QtWidgets
from typing import Any,Dict,List

'''
股票日数据更新工具
'''

class DailyUpdateWidget(QtWidgets.QWidget):
    signal_excute = QtCore.pyqtSignal(object)
    def __init__(self):
        super().__init__()

        self.thread_caculate: Thread = None

        self.init_data()
        self.init_ui()
        self.register_event()
        self.progress_init()
        pass
    def init_data(self):
        self.last_date_filename: str = 'last_date.xlsx'
        self.daily_pd_column_list: List = ["tradeDate", "preClosePrice", "actPreClosePrice", "openPrice",
                                           "highestPrice", "lowestPrice", "closePrice", "turnoverVol", "turnoverValue",
                                           "dealAmount", "turnoverRate", "accumAdjFactor", "negMarketValue",
                                           "marketValue", "chgPct", "PE", "PE1", "PB", "isOpen", "vwap"]
        pass
    def init_ui(self):
        self.setWindowTitle('股票日数据更新工具')
        self.setMinimumHeight(600)
        self.setMinimumWidth(600)

        self.caculate_progress = QtWidgets.QProgressBar()
        self.caculate_status_label = QtWidgets.QLabel()

        layout_progress = QtWidgets.QHBoxLayout()
        layout_progress.addWidget(self.caculate_progress)
        layout_progress.addWidget(self.caculate_status_label)

        clear_btn = QtWidgets.QPushButton('清空重选')
        clear_btn.clicked.connect(self.clear_btn_clicked)
        self.excute_btn = QtWidgets.QPushButton('更新日数据')
        self.excute_btn.clicked.connect(self.excute_btn_clicked)

        layout_one = QtWidgets.QHBoxLayout()
        layout_one.addWidget(clear_btn)
        layout_one.addWidget(self.excute_btn)
        layout_one.addStretch(1)

        results_put_dir_btn = QtWidgets.QPushButton('选择【结果放置目录】')
        results_put_dir_btn.clicked.connect(self.results_put_dir_btn_clicked)
        self.results_put_dir_lineedit = QtWidgets.QLineEdit()
        # self.results_put_dir_lineedit.setReadOnly(True)
        old_daily_dir_btn = QtWidgets.QPushButton('选择【未更新旧日数据目录】')
        old_daily_dir_btn.clicked.connect(self.old_daily_dir_btn_clicked)
        self.old_daily_dir_lineedit = QtWidgets.QLineEdit()
        # self.old_daily_dir_lineedit.setReadOnly(True)
        generater_old_daily_last_date_btn = QtWidgets.QPushButton('生成【未更新数据最后日期列表】')
        generater_old_daily_last_date_btn.clicked.connect(self.generater_old_daily_last_date_btn_clicked)
        self.generater_old_daily_last_date_lineedit = QtWidgets.QLineEdit()
        # self.generater_old_daily_last_date_lineedit.setReadOnly(True)
        now_stock_list_btn = QtWidgets.QPushButton('上传【当前最新股票列表文件】')
        now_stock_list_btn.clicked.connect(self.now_stock_list_btn_clicked)
        self.now_stock_list_lineedit = QtWidgets.QLineEdit()
        # self.now_stock_list_lineedit.setReadOnly(True)
        filter_update_stock_btn = QtWidgets.QPushButton('筛出【要更新的股票列表】')
        filter_update_stock_btn.clicked.connect(self.filter_update_stock_btn_clicked)
        self.filter_update_stock_lineedit = QtWidgets.QLineEdit()
        # self.filter_update_stock_lineedit.setReadOnly(True)
        new_stock_daily_contact_btn = QtWidgets.QPushButton('将合并股票日数据所在目录')
        new_stock_daily_contact_btn.clicked.connect(self.new_stock_daily_contact_btn_clicked)
        self.new_stock_daily_dir_lineedit = QtWidgets.QLineEdit()
        # self.new_stock_daily_dir_lineedit.setReadOnly(True)

        layout_two = QtWidgets.QFormLayout()
        layout_two.addRow(results_put_dir_btn,self.results_put_dir_lineedit)
        layout_two.addRow(old_daily_dir_btn,self.old_daily_dir_lineedit)
        layout_two.addRow(now_stock_list_btn,self.now_stock_list_lineedit)
        layout_two.addRow(generater_old_daily_last_date_btn,self.generater_old_daily_last_date_lineedit)
        layout_two.addRow(filter_update_stock_btn,self.filter_update_stock_lineedit)
        layout_two.addRow(new_stock_daily_contact_btn,self.new_stock_daily_dir_lineedit)

        tip_label = QtWidgets.QLabel('操作日志:')
        self.log_textedit = QtWidgets.QTextEdit()

        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(layout_progress)
        layout.addLayout(layout_one)
        layout.addLayout(layout_two)
        layout.addWidget(tip_label)
        layout.addWidget(self.log_textedit)
        self.setLayout(layout)
        pass
    def register_event(self):
        self.signal_excute.connect(self.process_excute_event)
        pass
    def process_excute_event(self,data:Dict[str,Any]):
        mark_str = data['mark_str']
        status = data['status']
        if status == 'error':
            self.thread_caculate = None
            self.progress_finished()
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                data['data'],
                QtWidgets.QMessageBox.Yes
            )
            return
        if mark_str == 'old_last_date':
            if status == 'waiting':
                self.write_log(data['data'])
            else:
                res_data = data['data']
                self.generater_old_daily_last_date_lineedit.setText(res_data)
                self.thread_caculate = None
                self.progress_finished()
                self.write_log('生成旧股票日数据最后日期列表完毕')
                QtWidgets.QMessageBox.information(
                    self,
                    '提示',
                    '生成旧股票日数据最后日期列表完毕',
                    QtWidgets.QMessageBox.Yes
                )
            pass
        elif mark_str == 'filter_stockcode':
            res_data = data['data']
            self.filter_update_stock_lineedit.setText(res_data)
            self.thread_caculate = None
            self.progress_finished()
            self.write_log('筛选待更新股票代码列表完毕')
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '筛选待更新股票代码列表完毕',
                QtWidgets.QMessageBox.Yes
            )
            pass
        elif mark_str == 'update_daily_data':
            if status == 'waiting':
                self.write_log(data['data'])
            else:
                self.thread_caculate = None
                self.progress_finished()
                self.write_log('股票日数据更新完毕')
                QtWidgets.QMessageBox.information(
                    self,
                    '提示',
                    '股票日数据更新完毕',
                    QtWidgets.QMessageBox.Yes
                )
                self.excute_btn.setDisabled(False)
                pass
        pass
    def clear_btn_clicked(self):
        self.old_daily_dir_lineedit.setText('')
        self.generater_old_daily_last_date_lineedit.setText('')
        self.now_stock_list_lineedit.setText('')
        self.filter_update_stock_lineedit.setText('')
        self.new_stock_daily_dir_lineedit.setText('')

        self.log_textedit.clear()
        pass
    def excute_btn_clicked(self):
        new_data_dir = self.new_stock_daily_dir_lineedit.text()
        if not new_data_dir:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请选择要用于追加的增量日数据所在文件夹',
                QtWidgets.QMessageBox.Yes
            )
            return
        results_dir = self.check_results_dir_excuted()
        if not results_dir:
            return
        old_dir = self.old_daily_dir_lineedit.text()
        if not old_dir:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请选择旧股票数据所在目录',
                QtWidgets.QMessageBox.Yes
            )
            return
        self.write_log('开始更新股票日数据。。。')
        self.excute_btn.setDisabled(True)
        mark_str = 'update_daily_data'
        pre_map = {
            'old_dir': old_dir,
            'results_dir': results_dir,
            'new_data_dir':new_data_dir
        }
        self.start_caculate_thread(mark_str, pre_map)
        pass
    def results_put_dir_btn_clicked(self):
        path = QtWidgets.QFileDialog.getExistingDirectory(
            self,
            '打开处理结果要放置的文件夹',
            '.'
        )
        if not path:
            return
        self.results_put_dir_lineedit.setText(path)
        pass
    def old_daily_dir_btn_clicked(self):
        path = QtWidgets.QFileDialog.getExistingDirectory(
            self,
            '打开当前股票日数据所在文件夹',
            '.'
        )
        if not path:
            return
        self.old_daily_dir_lineedit.setText(path)
        pass
    def check_results_dir_excuted(self):
        results_dir = self.results_put_dir_lineedit.text()
        results_dir = results_dir.strip()
        if not results_dir:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请先选择结果要放置的目录',
                QtWidgets.QMessageBox.Yes
            )
            return None
        return results_dir
    def generater_old_daily_last_date_btn_clicked(self):
        results_dir = self.check_results_dir_excuted()
        if not results_dir:
            return
        old_dir = self.old_daily_dir_lineedit.text()
        old_dir = old_dir.strip()
        if not old_dir:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请选择旧股票日数据所在的目录',
                QtWidgets.QMessageBox.Yes
            )
            return
        self.write_log('开始生成旧数据最后日期列表。。。')
        mark_str = 'old_last_date'
        pre_map = {
            'old_dir':old_dir,
            'results_dir':results_dir
        }
        self.start_caculate_thread(mark_str,pre_map)
        pass
    def now_stock_list_btn_clicked(self):
        path,_ = QtWidgets.QFileDialog.getOpenFileName(
            self,
            '打开最新股票列表文件',
            '.',
            'CSV(*.csv)'
        )
        if not path:
            return
        self.now_stock_list_lineedit.setText(path)
        pass
    def filter_update_stock_btn_clicked(self):
        results_dir = self.check_results_dir_excuted()
        if not results_dir:
            return
        last_date_file_path = self.generater_old_daily_last_date_lineedit.text()
        now_stock_list_file_path = self.now_stock_list_lineedit.text()
        if not last_date_file_path or not now_stock_list_file_path:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '旧股票日数据最后日期列表和最新股票列表必须都存在',
                QtWidgets.QMessageBox.Yes
            )
            return
        self.write_log('开始筛出需要更新的股票代码。。。')
        mark_str = 'filter_stockcode'
        pre_map = {
            'results_dir':results_dir,
            'last_date_file_path': last_date_file_path,
            'now_stock_list_file_path': now_stock_list_file_path
        }
        self.start_caculate_thread(mark_str, pre_map)
        pass
    def new_stock_daily_contact_btn_clicked(self):
        path = QtWidgets.QFileDialog.getExistingDirectory(
            self,
            '选择要用于追加的增量日数据所在文件夹',
            '.'
        )
        if not path:
            return
        self.new_stock_daily_dir_lineedit.setText(path)
        pass
    def write_log(self,log_str:str):
        now_str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        exist_str = self.log_textedit.toPlainText()
        pre_str = f'{now_str}:{log_str}\n{exist_str}'
        self.log_textedit.setPlainText(pre_str)
        pass
    def start_caculate_thread(self,mark_str:str,data:Dict[str,Any]):
        if self.thread_caculate:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '线程正在执行任务,请稍后。。。',
                QtWidgets.QMessageBox.Yes
            )
            return
        self.thread_caculate = Thread(
            target=self.running_caculate_thread,
            args=(
                mark_str,data,
            )
        )
        self.thread_caculate.start()
        self.progress_busy()
        pass
    def running_caculate_thread(self,mark_str:str,data:Dict[str,Any]):
        if mark_str == 'old_last_date':
            old_dir = data['old_dir']
            results_dir = data['results_dir']
            if not old_dir:
                res_map = {
                    'mark_str':mark_str,
                    'status':'error',
                    'data':'请选择待旧股票日数据文件夹'
                }
                self.signal_excute.emit(res_map)
                return
            if not results_dir:
                res_map = {
                    'mark_str': mark_str,
                    'status': 'error',
                    'data': '请选择结果放置的文件夹'
                }
                self.signal_excute.emit(res_map)
                return
            final_file_path = results_dir + os.path.sep + self.last_date_filename
            file_list = os.listdir(old_dir)
            res_list = []
            # tradeDate
            i = 1
            for file_item in file_list:
                if i%500 == 0:
                    res_map = {
                        'mark_str': mark_str,
                        'status': 'waiting',
                        'data': f'已处理{i}条'
                    }
                    self.signal_excute.emit(res_map)
                ticker = file_item.split('.')[0]
                file_path = old_dir + os.path.sep + file_item
                df = pd.read_csv(file_path,encoding='utf-8')
                last_date = df.iloc[-1]['tradeDate']
                res_list.append({
                    'ticker':ticker,
                    'last_date':last_date
                })
                i += 1
            res_df = pd.DataFrame(res_list)
            res_df.to_excel(final_file_path,engine='openpyxl')
            res_map = {
                'mark_str': mark_str,
                'status': 'success',
                'data': final_file_path
            }
            self.signal_excute.emit(res_map)
            pass
        elif mark_str == 'filter_stockcode':
            def pd_000(x):
                secID = x['secID']
                ticker = secID.split('.')[0]
                return ticker

            results_dir = data['results_dir']
            final_input_dir = results_dir + os.path.sep + 'waiting_update_code' + os.path.sep
            if not os.path.exists(final_input_dir):
                os.mkdir(final_input_dir)
            last_date_file_path = data['last_date_file_path']
            now_stock_list_file_path = data['now_stock_list_file_path']
            last_df = pd.read_excel(last_date_file_path,engine='openpyxl')
            now_df = pd.read_csv(now_stock_list_file_path,encoding='utf-8')
            now_df['ticker00'] = now_df.apply(pd_000,axis=1)
            exist_ticker_list = last_df['ticker'].values.tolist()
            add_df = now_df.loc[~now_df['ticker00'].isin(exist_ticker_list)]
            if len(add_df)>0:
                add_df.to_excel(final_input_dir+'add_codes.xlsx',engine='openpyxl')
            df_group = last_df.groupby(by='last_date')
            for name,group in df_group:
                name_str = name.replace('-','_').replace('/','_').replace(':','_')
                input_file_path = final_input_dir + name_str + '.xlsx'
                group.to_excel(input_file_path,engine='openpyxl')
                pass

            res_map = {
                'mark_str': mark_str,
                'status': 'success',
                'data': final_input_dir
            }
            self.signal_excute.emit(res_map)
            pass
        elif mark_str == 'update_daily_data':
            old_dir = data['old_dir']
            results_dir = data['results_dir']
            new_data_dir = data['new_data_dir']

            final_input_dir = results_dir + os.path.sep + 'new_daily' + os.path.sep
            if not os.path.exists(final_input_dir):
                os.mkdir(final_input_dir)
                pass
            new_file_list = os.listdir(new_data_dir)
            new_ticker_list = []
            i = 1
            for file_item in new_file_list:
                file_path = new_data_dir + os.path.sep + file_item
                df = pd.read_csv(file_path,encoding='utf-8')
                df_group = df.groupby(by='secID')
                for name,group in df_group:
                    if i%100 == 0:
                        res_map = {
                            'mark_str': mark_str,
                            'status': 'waiting',
                            'data': f"数据已处理{i}条"
                        }
                        self.signal_excute.emit(res_map)
                    ticker00 = name.split('.')[0]
                    new_ticker_list.append(ticker00)
                    old_file_path = old_dir + os.path.sep + ticker00 + '.csv'
                    if not os.path.exists(old_file_path):
                        # 新上市的股票
                        new_final_path = final_input_dir + ticker00 + '.csv'
                        node_df = group.loc[:,self.daily_pd_column_list].copy()
                        node_df.to_csv(new_final_path,encoding='utf-8')
                        pass
                    else:
                        # 做增量更新的股票
                        # 1 将旧股票文件copy到新目录下
                        shutil.copy(old_file_path,final_input_dir)
                        # 2 读取旧股票日数据,并将新数据追加到其后面
                        old_final_path = final_input_dir + ticker00 + '.csv'
                        old_df = pd.read_csv(old_final_path,encoding='utf-8')
                        old_df = old_df.loc[:,self.daily_pd_column_list].copy()
                        node_df = group.loc[:,self.daily_pd_column_list].copy()
                        two_df = pd.concat([old_df,node_df])
                        two_df.to_csv(old_final_path,encoding='utf-8')
                        pass
                    i += 1
                    pass
            # 把这次没有更新的股票日数据文件复制到新目录下
            res_map = {
                'mark_str': mark_str,
                'status': 'waiting',
                'data': f"开始迁移无需更新的日数据文件"
            }
            self.signal_excute.emit(res_map)
            old_file_list = os.listdir(old_dir)
            for file_item in old_file_list:
                ticker00 = file_item.split('.')[0]
                if ticker00 in new_ticker_list:
                    continue
                old_file_path = old_dir + os.path.sep + ticker00 + '.csv'
                shutil.copy(old_file_path, final_input_dir)

            res_map = {
                'mark_str': mark_str,
                'status': 'success',
                'data': '日数据更新完毕'
            }
            self.signal_excute.emit(res_map)
            pass
        pass
    def progress_init(self) -> None:
        self.caculate_progress.setValue(0)
        self.caculate_status_label.setText('无任务')
    def progress_busy(self) -> None:
        self.caculate_progress.setRange(0, 0)
        self.caculate_status_label.setText('正在执行')
    def progress_finished(self) -> None:
        self.caculate_progress.setRange(0, 100)
        self.caculate_progress.setValue(100)
        self.caculate_status_label.setText('执行完毕')
        pass


if __name__ == '__main__':
    QtCore.QCoreApplication.setAttribute(QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
    app = QtWidgets.QApplication(sys.argv)
    main_window = DailyUpdateWidget()
    main_window.show()
    app.exec()
    pass



股票日数据下载:

旧日数据包(更新至2023-07-17)。后续只分享增量部分,增量的数据自行通过工具同步即可,大概率每周末更新。链接挂在这里。

旧日数据包(更新至2023-07-17)

链接:https://pan.baidu.com/s/1Ez5xA8bI4prlpEiAay019g 
提取码:cg30

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

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

相关文章

【机器学习】吴恩达课程2-单变量线性回归

一、单变量线性回归 1. 模型描述 监督学习的流程 & 单变量线性回归函数 代价函数:,其中 m 表示训练样本的数量 公式为预测值与实际值的差,平方为最小二乘法和最佳平方/函数逼近。 目标:最小化代价函数,即 2. 只…

PR模板-33组故障干扰文字标题动画 Motion Glitch Typography

Motion Glitch Typography包含33组故障干扰文字标题动画pr模板。不需要任何插件或脚本,只需点击几下,您的视频就有很酷的故障标题动画,适用于预告片、宣传片或任何类型的视频。 适用软件:Premiere Pro 2020 或更高版本 分辨率&a…

Go语言之函数补充defer语句,递归函数,章节练习

defer语句是go语言提供的一种用于注册延迟调用的机制,是go语言中一种很有用的特性。 defer语句注册了一个函数调用,这个调用会延迟到defer语句所在的函数执行完毕后执行,所谓执行完毕是指该函数执行了return语句、函数体已执行完最后一条语句…

密码学学习笔记(十四):SHA-3 Sponge Construction - 海绵结构

SHA-3算法满足了哈希函数的三个安全属性,并且和SHA-2的变体达到同样级别的安全性。此外,SHA-3算法不容易受到长度扩展攻击,并可用于计算秘密消息的哈希值。 SHA-3是一种建立在Permutation(置换)之上的密码算法。 置换就是假设有两个数组a和…

Hadoop第一课之环境配置

1.配置一个模板机 要求:IP DNS地址页 网址 防火墙 安装包 1.ip ifconfig 查询 先用虚拟机看一下自己的网关 vim search/provides 命令 查找 # 修改网络配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33 如果提示找不到vim命令,使用yum下载v…

Springboot Excel 最简单的 多sheet表 导入导出

前言 上周学习群里有人问到,多个sheet的导出导入,我第一反应就是easypoi不是自己就有方法了么? 后面一想,可能有些看客还处于是 找工具类,然后调试 的写代码 的 阶段,可能还不会去看jar包的一些函数。 既然…

SpringMVC入门篇5 --- 拦截器

目录 1. 简介 拦截器(Interceptor)是一种动态拦截方法调用的机制。 作用: 在指定的方法调用前后执行预先设定后的代码。阻止原始方法的执行。 拦截器与过滤器的区别 归属不同:Filter属于Servlet技术,Interceptor…

使用vue3 + Ts + Vite + ElementPlus实现一个抽奖程序

一. 说明 这是一个通过vue3 Ts Vite ElementPlus实现的一个抽奖程序。项目链接 二. 整体架构与功能描述 左侧设置了奖品说明,每个奖项配有文字和图片简介。总共设置了四个奖项,分别是特等奖1名,一等奖2名,二等奖5名&#xf…

平安养老险党委书记、董事长甘为民:聚焦养老主业 助推养老保障事业高质量发展

每经记者 涂颖浩 每经编辑 马子卿 随着人口老龄化趋势加剧,中国养老金融市场呈现出巨大的潜力,逐步迈入养老新时代。近日,平安养老险党委书记、董事长甘为民在接受《每日经济新闻》记者专访时表示,过往单纯的养老发展模式难以满足…

Jmeter性能测试 —— 性能测试的概念

性能测试的概念 性能测试是指通过特定方式,对被测系统按照一定策略施加压力,获取系统 响应时间、TPS(Transaction Per Second)、吞吐量、资源利用率等性能指标,以期保证生产系统的性能能够满足用户需求的过程。 性能…

浅析编译与链接

生成可执行文件的四个过程 当编写和构建计算机程序时,预处理、编译、汇编和链接是将源代码转化为可执行程序的关键过程。以下是对每个阶段的详细解释: 1. 预处理(Preprocessing):将.c/.cpp文件中的头文件展开、宏展开…

【PostgreSQL内核学习(一)—— Ubuntu源码安装PostgreSQL】

Ubuntu源码安装PostgreSQL 1. PostgreSQL官网下载压缩包2. 解压&安装2.1 解压文件2.2 安装依赖2.3 执行安装2.4 执行安装2.5 添加路径到文件 3. 初始化数据库与使用3.1 初始化数据库3.2 启动数据库服务3.3 启动数据库 1. PostgreSQL官网下载压缩包 下载地址:ht…

【黑马头条之freemarker入门】

本笔记内容为黑马头条项目的freemarker部分 目录 一、freemarker 介绍 二、环境搭建&&快速入门 1、创建测试工程 2、配置文件 3、创建模型类 4、创建模板 5、创建controller 6、创建启动类 7、测试 三、freemarker基础 1、基础语法种类 2、集合指令&#…

【iOS】—— 面向对象,Runtime,ARC等问题总结

对于暑假学习大多数是对之前学习的一个复习,在这里只做对之前学习欠缺知识的补充以及这些知识点涉及的一些问题,从问题入手学习。 文章目录 面向对象1.一个NSObject对象占多少内存?2.对象的isa指针指向哪里?3.OC的类信息存放在哪…

PLSQL编程

1.概念和目的 1.1. 什么是PL/SQL? PL/SQL(Procedure Language/SQL) 是Oracle对sql语言的过程化扩展 (类似于Basic); 指在SQL命令语言中增加了过程处理语句(如分支、循环等),使SQL语言具有过程处理能力。…

Spring @Autowired 注解原理

Spring Autowired 注解原理 1.Autowired 使用 ComponentScan("org.example.bean") public class AnnoContextDemo {Autowiredprivate User user;public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplic…

Ultipa嬴图数据库 | 深圳国际金融科技大赛圆满落幕

2023年7月13日,由深圳市地方金融监督管理局、深圳市福田区人民政府、深圳市南山区人民政府指导,招商局金融科技有限公司主办的2022深圳国际金融科技大赛总决赛在福田区圆满落幕。经过从初赛到决赛,共计103个项目的激烈角逐,Ultipa…

Unity视角拉近时物体缺失的问题处理

在Unity的开发过程中,我们可能会遇到以下情况: 就是在场景的不断编辑中,突然又一次打开场景,再拉近或拉远场景视角时,会出现场景中的对象会显示不全的问题。 出现了这样的情况会让场景的预览很不友好。 出现这个问题的…

【006】面向 6G 的深度图像语义通信模型

摘要 目前的语义通信模型在处理图像数据方面仍有可改善的部分,包括有效的图像语义编解码、高效的语义模型训练和精准的图像语义评估。为此,提出了一种深度图像语义通信(DeepISC)模型。首先采用基于 vision transformer 的自编码器…

数字IC后端设计实现中的Post-mask ECO应该怎么做?

在数字IC后端设计实现中,我们经常会涉及到芯片需要做Function ECO。常见的Function ECO可以分为pre mask ECO和post mask ECO两种。因此,作为一个数字IC后端工程师,必须熟练掌握这两种Function ECO的实现流程及其实现技巧。 两者的区别在于&…